Nessun oggetto della modifica
Etichetta: Annullato
Nessun oggetto della modifica
Etichetta: Annullato
Riga 1: Riga 1:
<!doctype html>
<html>
<html lang="it">
<head>
<head>
  <meta charset="utf-8" />
<meta charset="utf-8">
  <title>🔧 Dashboard Operativa – Masticationpedia</title>
<title>Dashboard Operativa – Masticationpedia</title>
   <meta name="viewport" content="width=device-width, initial-scale=1" />
<style>
   <style>
   :root{--b:#e5e7eb;--bg:#f9fafb;--card:#ffffff;--txt:#1f2937;--muted:#6b7280;--blue:#0a7cff;--green:#28a745;}
    body{font:15px/1.55 system-ui,-apple-system,Segoe UI,Roboto,Arial,sans-serif;color:#1f2328;background:#fafafa;margin:18px}
   body{background:var(--bg);color:var(--txt);font:16px/1.5 system-ui,-apple-system,Segoe UI,Roboto,Arial,sans-serif}
    h2{margin:.2rem 0 0.6rem 0}
  .toolbar{display:flex;gap:10px;flex-wrap:wrap;margin:16px 0}
    .dashboard-toggle{background:#fff;border:1px solid #ddd;border-radius:10px;padding:.5rem .9rem;cursor:pointer}
  .btn{border:1px solid var(--b);background:var(--card);border-radius:10px;padding:10px 14px;font-weight:600;cursor:pointer}
    .dashboard-box{background:#fdfdfd;border:1px solid #ddd;border-radius:10px;padding:1rem}
  .btn.primary{background:var(--blue);color:#fff;border-color:var(--blue)}
    input,textarea,select,button{font:inherit}
  .btn.danger{background:#e11d48;color:#fff;border-color:#e11d48}
    input,textarea,select{border:1px solid #ccc;border-radius:8px;padding:.45rem .6rem}
  .link{font-weight:600}
    button{border:1px solid #ddd;border-radius:8px;background:#fff;cursor:pointer}
  .dash-box{background:var(--card);border:1px solid var(--b);border-radius:12px;padding:16px;margin-top:14px}
    button.primary{background:#0a7cff;border-color:#0a7cff;color:#fff}
  .gpt-card{background:#fff;border:1px solid #e6e6e6;border-radius:10px;padding:16px;box-shadow:0 1px 2px rgba(0,0,0,.04)}
    .gpt-card{background:#fff;border:1px solid #e6e6e6;border-radius:10px;padding:16px;box-shadow:0 1px 2px rgba(0,0,0,.04)}
  .muted{color:var(--muted)}
    .muted{color:#666}
  .row{display:flex;gap:10px;align-items:center;flex-wrap:wrap}
    .list{max-height:220px;overflow:auto;border:1px solid #eee;border-radius:10px;background:#fff;padding:8px;font-family:ui-monospace,Menlo,Consolas,monospace;font-size:12px}
  .grid2{display:grid;grid-template-columns:1fr 1fr;gap:10px}
   </style>
  input[type=text], input[type=number], select, textarea{width:100%;border:1px solid var(--b);border-radius:8px;padding:8px}
  textarea{min-height:120px}
  ul.plain{list-style:none;padding-left:0;margin:0}
  .pill{border:1px solid var(--b);border-radius:999px;padding:2px 8px;font-size:12px;color:var(--muted)}
  .list-item{display:flex;align-items:center;gap:8px;justify-content:flex-start;margin:6px 0}
  .list-item .actions{display:flex;gap:6px}
   code{background:#f3f4f6;border:1px solid #e5e7eb;border-radius:6px;padding:2px 6px}
</style>
</head>
</head>
<body>
<body>


<h2>🔧 Dashboard Operativa – Masticationpedia</h2>
<h2>🔧 Dashboard Operativa – Masticationpedia</h2>
<p class="muted"><em>Centro di comando per progetti, API, file e backup</em></p>
<p class="muted">Centro di comando per progetti, API, file e backup</p>


<a href="/dashboard/api/log_view.php" target="_blank">🧾 Apri Log Dashboard</a>
<div class="row">
<button onclick="clearServerLog()">🧹 Svuota Log</button>
  <a class="link" href="/dashboard/api/log_view.php" target="_blank">🧾 Apri Log Dashboard</a>
  <button class="btn" onclick="clearServerLog()">🧹 Svuota Log</button>
</div>


<!-- 🔘 Pulsanti di navigazione -->
<!-- Pulsanti principali -->
<div style="margin: 1rem 0 1.2rem 0; display:flex; flex-wrap:wrap; gap:.6rem;">
<div class="toolbar">
   <button class="dashboard-toggle" onclick="toggleDashboardBox('api-settings')">⚙️ Connessione API</button>
   <button class="btn" onclick="showBox('api-settings')">⚙️ Connessione API</button>
   <button class="dashboard-toggle" onclick="toggleDashboardBox('project-status')">📊 Stato Progetti</button>
   <button class="btn" onclick="showBox('project-status')">📊 Stato Progetti</button>
   <button class="dashboard-toggle" onclick="toggleDashboardBox('chatgpt-plus')">🤖 ChatGPT plus</button>
   <button class="btn" onclick="showBox('test-tools')">🧪 Strumenti di Test</button>
  <button class="dashboard-toggle" onclick="toggleDashboardBox('test-tools')">🧪 Strumenti di Test</button>
   <button class="btn" onclick="showBox('activity-log')">📘 Registro Attività</button>
   <button class="dashboard-toggle" onclick="toggleDashboardBox('activity-log')">📘 Registro Attività</button>
  <button class="dashboard-toggle" onclick="uploadToOpenAI()">📄 Carica in OpenAI</button>
</div>
</div>


<!-- 📦 Connessione API (via server, nessuna key lato client) -->
<!-- =========================
<div id="api-settings" class="dashboard-box" style="display:none;">
    ⚙️ Connessione API (proxy)
    ========================= -->
<div id="api-settings" class="dash-box" style="display:none">
   <strong>Connessione API (protetta dal server)</strong><br><br>
   <strong>Connessione API (protetta dal server)</strong><br><br>
 
  <div class="grid2">
  <label>Modello</label>
    <div>
  <select id="model-select" style="width:100%; margin-bottom:0.5rem;">
      <label>Modello</label>
    <option value="gpt-4o-2024-05-13" selected>gpt-4o-2024-05-13</option>
      <select id="model-select">
    <option value="gpt-4o-mini">gpt-4o-mini</option>
        <option value="gpt-4o-2024-05-13" selected>gpt-4o-2024-05-13</option>
    <option value="gpt-4-turbo-2024-04-09">gpt-4-turbo-2024-04-09</option>
        <option value="gpt-4o-mini">gpt-4o-mini</option>
  </select>
        <option value="gpt-4-turbo-2024-04-09">gpt-4-turbo-2024-04-09</option>
 
      </select>
  <label>Prompt di test</label>
    </div>
  <textarea id="test-prompt" rows="3" style="width:100%; margin-bottom:0.5rem;">Dimmi una curiosità sulla mandibola</textarea><br>
    <div>
 
      <label>Prompt di test</label>
  <button class="primary" onclick="testAPIConnection()">▶️ Esegui</button>
      <input id="test-prompt" type="text" value="Dimmi una curiosità sulla mandibola">
  <pre id="api-result" style="background:#f0f0f0; padding:1rem; border:1px solid #ccc; margin-top:1rem; white-space:pre-wrap;"></pre>
    </div>
</div>
 
<!-- 📊 Stato Progetti -->
<div id="project-status" class="dashboard-box" style="display:block; margin-top:1rem;">
  <strong>📊 Stato Progetti</strong><br><br>
 
  <!-- 🧠 Risposta GPT – Analisi progetto -->
<!-- === Parametri per GPT (come prima) === -->
<div id="gptParams" class="dashboard-box" style="margin-top:12px; border-style:dashed;">
  <div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;">
    <input id="p_goal"        placeholder="🎯 Obiettivo (es. Attivare SSO MediaWiki classico)" />
    <input id="p_audience"    placeholder="👥 Pubblico (es. amministratori, sviluppatori)" />
    <input id="p_deliverable" placeholder="📦 Output atteso (patch LocalSettings + file PHP)" />
    <input id="p_constraints" placeholder="⏱️ Vincoli (MW 1.43, evitare conflitti)" />
   </div>
   </div>
   <div style="margin-top:10px;">
   <div class="row" style="margin-top:10px">
     <button id="btnAnalyze" class="primary">Analizza con GPT</button>
     <button class="btn primary" onclick="testAPIConnection()">▶️ Esegui</button>
    <span class="pill">via <code>/dashboard/api/openai_project_gpt.php</code></span>
   </div>
   </div>
  <pre id="api-result" class="dash-box" style="white-space:pre-wrap;margin-top:12px"></pre>
</div>
</div>


<!-- === Gestione Progetti (come prima) === -->
<!-- =====================
<div class="projects-controls dashboard-box" style="margin-top:1rem; background:#fff;">
    📊 STATO PROGETTI
  <h4>📂 Gestione Progetti</h4>
    ===================== -->
  <div style="display:flex;gap:6px;flex-wrap:wrap;">
<div id="project-status" class="dash-box" style="display:block">
    <input id="newProjectName" type="text" placeholder="Nome progetto (A-Z 0-9 _ -)">
  <strong>📊 Stato Progetti</strong>
    <button id="btnCreateProject" class="primary">Crea progetto</button>
  </div>
  <ul id="projectsList" class="projects-list" style="margin-top:1rem; list-style:none; padding:0;"></ul>
</div>


 
  <!-- 🧠 Risposta GPT -->
<!-- 🤖 ChatGPT plus (stato attuale) -->
  <div style="margin-top: 12px">
<div id="chatgpt-plus" class="dashboard-box" style="display:none; margin-top:1rem;">
     <label><strong>🧠 Risposta GPT – Analisi progetto:</strong></label>
  <strong>ChatGPT plus – Generazione capitoli</strong><br><br>
     <div id="gptResponse" class="gpt-card">
 
      <em class="muted">Qui apparirà la risposta generata da GPT sull’analisi del progetto…</em>
  <!-- Barra superiore -->
     </div>
  <div style="display:flex; gap:12px; flex-wrap:wrap; margin-bottom:10px;">
     <label>📁 Progetto:
      <select id="mpChatProject">
        <option value="Generazione_capitoli" selected>Generazione capitoli</option>
      </select>
    </label>
     <label>⚙️ Modalità:
      <select id="mpChatMode">
        <option value="analysis">Analisi</option>
        <option value="rewrite">Riscrittura</option>
        <option value="generate">Genera capitolo</option>
        <option value="biblio">Bibliografia</option>
      </select>
     </label>
   </div>
   </div>


   <!-- Allegati -->
   <!-- Parametri -->
   <div style="display:flex; gap:8px; align-items:center; flex-wrap:wrap; margin-bottom:8px;">
   <div class="dash-box" style="margin-top:12px;border-style:dashed">
     <input id="mpChatFile" type="file" multiple />
     <div class="grid2">
    <span id="mpChatDrop" style="border:1px dashed #bbb; padding:6px 10px; border-radius:8px; cursor:pointer; user-select:none;">
      <input id="p_goal"       placeholder="🎯 Obiettivo (es. Attivare SSO MediaWiki classico)">
      Trascina qui file (solo elenco, non inviati)
      <input id="p_audience"   placeholder="👥 Pubblico (es. amministratori, sviluppatori)">
    </span>
      <input id="p_deliverable" placeholder="📦 Output atteso (es. patch LocalSettings + file PHP)">
  </div>
      <input id="p_constraints" placeholder="⏱️ Vincoli (es. MediaWiki 1.43, evitare conflitti)">
  <div id="mpChatFiles" style="display:flex; gap:8px; flex-wrap:wrap; margin-bottom:8px;"></div>
    </div>
 
    <div class="row" style="margin-top:10px">
  <!-- Input domanda -->
      <button id="btnAnalyze" class="btn primary">Analizza con GPT</button>
  <label><b>Domanda</b> (breve, come in ChatGPT):</label>
      <span class="pill">usa <code>/dashboard/api/openai_project_gpt.php</code></span>
  <div style="display:flex; gap:8px; align-items:flex-start; margin-bottom:8px;">
    </div>
    <textarea id="mpChatPrompt" rows="3" style="flex:1 1 auto; width:100%;"></textarea>
    <button id="mpChatSend">Invia</button>
   </div>
   </div>


   <!-- Output risposta -->
   <!-- 📂 Gestione Progetti -->
  <label><b>Risposta</b> (box grande):</label>
   <div class="dash-box" style="margin-top:12px;background:#fff">
   <div id="mpChatAnswer" style="min-height:220px; border:1px solid #ddd; background:#fff; border-radius:8px; padding:10px; white-space:pre-wrap;"></div>
    <h4>📂 Gestione Progetti</h4>
 
     <div class="row">
  <!-- Explorer semplice dei file salvati -->
       <input id="newProjectName" type="text" placeholder="Nome progetto (A-Z 0-9 _ -)" style="max-width:300px">
  <div style="margin-top:10px; border-top:1px dashed #ddd; padding-top:10px;">
      <button id="btnCreateProject" class="btn primary">Crea progetto</button>
     <div style="display:flex; align-items:center; gap:8px; margin-bottom:6px;">
       <strong>🗂️ File salvati (output/)</strong>
      <button id="mpChatRefresh"
        title="Aggiorna elenco"
        onclick="window.__forceRefreshList && window.__forceRefreshList()">Aggiorna</button>
    </div>
    <div id="mpSavedList" class="list">
      <em style="color:#777;">Nessun file elencato. Clicca “Aggiorna”.</em>
     </div>
     </div>
  </div>


  <!-- Azioni -->
    <ul id="projectsList" class="plain" style="margin-top:10px">
  <div style="margin-top:8px; display:flex; gap:8px; justify-content:flex-end;">
      <!-- popolato via JS -->
    <button id="mpChatClear">Pulisci</button>
     </ul>
     <button id="mpChatCopy">Copia risposta</button>
    <button id="mpChatSave">📥 Salva risposta</button>
   </div>
   </div>
</div>
</div>


<!-- 📁 Importa file dal server (semplificata) -->
<!-- =====================
<div id="serverFileSimpleImportContainer" class="dashboard-box" style="margin-top:1rem;">
    🧪 STRUMENTI DI TEST
   <h4>📁 Importa file dal server (semplificata)</h4>
    ===================== -->
 
<div id="test-tools" class="dash-box" style="display:none">
   <!-- Nuovo bottone: Copia sanificato → progetto -->
   <strong>Console JS</strong>
  <div style="margin:.4rem 0 .6rem 0;">
   <textarea id="codeArea" placeholder="Scrivi codice JS da testare…"></textarea>
    <button class="primary" onclick="copyFromServerSanitized()">🔐 Copia (sanificato) → progetto</button>
  <div class="row" style="margin-top:10px">
    <small class="muted" style="display:block;margin-top:6px;">
     <button class="btn" onclick="runTestCode()">▶️ Esegui</button>
      Compila i campi in basso (Project/Subfolder/Filename) per decidere la destinazione nel progetto.
     <button class="btn" onclick="checkCodeAI()">🔍 Controlla con AI</button>
     </small>
  </div>
 
  <div style="display:grid;grid-template-columns:1fr;gap:6px;max-width:820px;">
    <label for="sourcePathInput"><b>📂 Percorso Assoluto del file sorgente (SERVER):</b></label>
     <input type="text" id="sourcePathInput" placeholder="/var/www/html/masticationpedia-staging/LocalSettings.php" />
   </div>
   </div>
  <pre id="consoleOutput" class="dash-box" style="background:#111;color:#0f0;white-space:pre-wrap"></pre>
</div>
</div>


<!-- 📁 Caricamento/lettura File GPT (destinazione) -->
<!-- =====================
<div class="dashboard-box" style="margin-top:1rem;">
    📘 REGISTRO ATTIVITÀ
  <h3>📁 Carica/Leggi File GPT</h3>
    ===================== -->
  <div style="display:flex;gap:8px;flex-wrap:wrap;align-items:center;">
<div id="activity-log" class="dash-box" style="display:none">
    <label>📁 Project: <input type="text" id="gpt-load-project" value="Test_Dashboard_OK" /></label>
  <div class="row" style="justify-content:space-between">
     <label>📂 Subfolder: <input type="text" id="gpt-load-subfolder" value="php" /></label>
     <strong>📘 Registro attività</strong>
     <label>📄 Filename: <input type="text" id="gpt-load-filename" placeholder="es: LocalSettings.php" /></label>
     <button class="btn danger" onclick="clearActivityLog()">🧹 Svuota</button>
    <button onclick="caricaFileGPT()">📖 Leggi file</button>
   </div>
   </div>
</div>
   <div id="activityLogContent" class="dash-box" style="margin-top:10px;max-height:260px;overflow:auto;font-family:monospace;font-size:13px">
 
     <em class="muted">Registro avviato…</em>
<!-- 🧪 Console JS -->
<div id="test-tools" class="dashboard-box" style="display:none; margin-top:1rem;">
   <strong>Console JS:</strong><br>
  <textarea id="codeArea" placeholder="Scrivi codice JS da testare..." style="width:100%; height:100px;"></textarea><br>
  <button onclick="checkCodeAI()">🔍 Controlla con AI</button>
  <pre id="consoleOutput" style="background:#000; color:#0f0; padding:1rem; border-radius:8px; font-family:monospace;"></pre>
</div>
 
<!-- 📘 Registro Attività -->
<div id="activity-log" class="dashboard-box" style="display:none; margin-top:1rem;">
  <strong>📘 Registro attività:</strong>
  <button onclick="clearActivityLog()" style="float:right; background:#e74c3c; color:white; border:none; padding:0.4rem 1rem; border-radius:6px; font-weight:bold;">🧹 Svuota</button>
  <div id="activityLogContent" style="margin-top:1rem; max-height:250px; overflow-y:auto; background:#f0f0f0; padding:1rem; border:1px solid #ccc; border-radius:6px; font-family:monospace; font-size:0.85rem;">
     <em><span style="color:#888;">Registro avviato...</span></em>
   </div>
   </div>
</div>
</div>


<!-- ✅ Carica JS esterno (se lo usi) -->
<!-- =====================
<script src="/dashboard/api/dashboard.js?v=20250907d"></script>
    JS
    ===================== -->
<script>
/* ---------- util UI ---------- */
function showBox(id){
  ['api-settings','project-status','test-tools','activity-log'].forEach(x=>{
    const el = document.getElementById(x);
    if (el) el.style.display = (x===id?'block':'none');
  });
}


<!-- ============ JS inline ============ -->
/* ---------- log ---------- */
<script>
function logActivity(msg){
/* UI base */
   const box = document.getElementById('activityLogContent');
function toggleDashboardBox(id){
   if(!box) return;
   const el = document.getElementById(id);
   const t = new Date().toLocaleTimeString('it-IT');
   if (!el) return;
  const line = document.createElement('div');
   el.style.display = (el.style.display === 'block' ? 'none' : 'block');
  line.innerHTML = '<span class="muted">['+t+']</span> ' + msg;
  box.prepend(line);
}
function clearActivityLog(){
  const box = document.getElementById('activityLogContent');
  if (box) { box.innerHTML = '<em class="muted">Registro svuotato.</em>'; logActivity('🧹 Log svuotato.'); }
}
}


/* Log: svuota lato server (log_clear.php già configurato) */
/* ---------- svuota log server ---------- */
async function clearServerLog(){
async function clearServerLog(){
  if (!confirm('Svuotare il Log Dashboard?')) return;
   try{
   try{
     const r = await fetch('/dashboard/api/log_clear.php', { method:'POST', credentials:'include' });
     const r = await fetch('/dashboard/api/log_clear.php', {credentials:'include'});
     const j = await r.json();
     const j = await r.json();
     if (j.ok){
     if (j.ok){
       alert('Log svuotato');
       alert('Log svuotato.\n' + (j.cleared||[]).join('\n'));
       window.open('/dashboard/api/log_view.php?n=300', '_blank');
      logActivity('🧹 Log server svuotato');
       window.open('/dashboard/api/log_view.php?n=300','_blank');
     }else{
     }else{
       alert('Errore: '+(j.error||'operazione fallita'));
       alert('Errore svuota log: ' + (j.error||''));
     }
     }
   }catch(e){ alert('Errore rete: '+e.message); }
   }catch(e){ alert('Errore rete: '+e.message); }
}
}


/* API proxy test (già esistente lato server) */
/* ---------- renderer GPT ---------- */
async function testAPIConnection(){
  const prompt = (document.getElementById('test-prompt')?.value||'').trim();
  const output = document.getElementById('api-result');
  const model  = document.getElementById('model-select')?.value || 'gpt-4o-2024-05-13';
  if (!prompt){ output.innerText='⚠️ Inserisci un prompt di test.'; return; }
  output.innerText='⏳ Contatto il proxy sul server...';
  try{
    const res = await fetch('/dashboard/api/openai_project_gpt.php', {
      method:'POST', headers:{'Content-Type':'application/json'}, credentials:'include',
      body: JSON.stringify({ prompt, model })
    });
    const data = await res.json();
    if (data.status==='ok' && data.result){
      output.innerText = '✅ Risposta: '+data.result;
    } else {
      output.innerText = '❌ Errore: ' + (data.error || 'Risposta vuota');
    }
  }catch(e){ output.innerText='🚫 Errore di rete: '+e.message; }
}
 
/* Renderer stile ChatGPT per la risposta GPT */
function renderGpt(text){
function renderGpt(text){
   const box = document.getElementById('gptResponse');
   const box = document.getElementById('gptResponse');
Riga 249: Riga 188:
     .replace(/^\s*#{3}\s?(.*)$/gm,'<h3 style="font-size:18px;margin:14px 0 6px;">$1</h3>')
     .replace(/^\s*#{3}\s?(.*)$/gm,'<h3 style="font-size:18px;margin:14px 0 6px;">$1</h3>')
     .replace(/^\s*#{2}\s?(.*)$/gm,'<h2 style="font-size:20px;margin:16px 0 8px;">$1</h2>')
     .replace(/^\s*#{2}\s?(.*)$/gm,'<h2 style="font-size:20px;margin:16px 0 8px;">$1</h2>')
     .replace(/^\s*#\s?(.*)$/gm, '<h1 style="font-size:22px;margin:18px 0 10px;">$1</h1>')
     .replace(/^\s*#\s?(.*)$/gm,'<h1 style="font-size:22px;margin:18px 0 10px;">$1</h1>')
     .replace(/^\s*-\s+(.*)$/gm, '<li>$1</li>');
     .replace(/^\s*-\s+(.*)$/gm,'<li>$1</li>');
   html = html.replace(/(?:<li>.*<\/li>\n?)+/gs, m => `<ul style="margin:8px 0 14px 22px;">${m}</ul>`);
   html = html.replace(/(?:<li>.*<\/li>\n?)+/gs, m => `<ul style="margin:8px 0 14px 22px;">${m}</ul>`);
   html = html.split('\n').map(line=>{
   html = html.split('\n').map(line=>{
     if (/^<h\d|^<ul|^<li|^<\/ul>/.test(line)) return line;
     if (/^<h\d|^<ul|^<li|^<\/ul>/.test(line)) return line;
     if (line.trim()==='') return '';
     if (line.trim()==='') return '';
     return `<p style="margin:6px 0;">${line}</p>`;
     return `<p style="margin:8px 0;">${line}</p>`;
   }).join('');
   }).join('');
   box.innerHTML = html;
   box.innerHTML = html;
}
}


/* Costruzione prompt da parametri progetto */
/* ---------- prompt per GPT ---------- */
function buildProjectContext(){
  const goal        = (document.getElementById('p_goal')?.value||'').trim();
  const audience    = (document.getElementById('p_audience')?.value||'').trim();
  const deliverable = (document.getElementById('p_deliverable')?.value||'').trim();
  const constraints = (document.getElementById('p_constraints')?.value||'').trim();
  return {goal,audience,deliverable,constraints};
}
function buildPromptForGPT(){
function buildPromptForGPT(){
   const c = buildProjectContext();
  const g  = (document.getElementById('p_goal')?.value || '').trim();
  const a  = (document.getElementById('p_audience')?.value || '').trim();
  const d  = (document.getElementById('p_deliverable')?.value || '').trim();
   const c = (document.getElementById('p_constraints')?.value || '').trim();
 
   const out = [];
   const out = [];
   out.push('Rispondi in ITALIANO. Sei un architetto software MediaWiki+PHP.');
   out.push('Sei un project designer senior. Rispondi in italiano con piano chiaro, operativo.');
   out.push('\n# Output atteso\n- Executive Summary\n- Rischi e mitigazioni\n- Piano step-by-step (milestones)\n- File da toccare/creare\n- Test e rollback');
   if (g) out.push('\\n# Obiettivo\\n'+g);
   if (c.goal) out.push('\n# Obiettivo\n'+c.goal);
   if (a) out.push('\\n# Pubblico\\n'+a);
   if (c.audience) out.push('\n# Pubblico\n'+c.audience);
   if (d) out.push('\\n# Output atteso\\n'+d);
   if (c.deliverable) out.push('\n# Deliverable\n'+c.deliverable);
   if (c) out.push('\\n# Vincoli\\n'+c);
   if (c.constraints) out.push('\n# Vincoli\n'+c.constraints);
   out.push('\\n# Output richiesto\\n- Executive Summary\\n- Punti di forza & rischi\\n- Piano step-by-step (milestones)\\n- Risorse & budget\\n- Metriche di successo');
   return out.join('\n');
   return out.join('\\n');
}
}


/* Analisi con GPT via proxy (usa endpoint già esistente) */
/* ---------- analisi con GPT (via proxy server) ---------- */
async function runProjectAnalysis(){
async function runProjectAnalysis(){
   const btn = document.getElementById('btnAnalyze');
   const btn = document.getElementById('btnAnalyze');
  if (!btn) return;
   btn.disabled = true; btn.textContent = 'Analizzo…';
   btn.disabled = true; btn.textContent='Analizzo…';
   try{
   try{
    const model  = document.getElementById('model-select')?.value || 'gpt-4o-2024-05-13';
     const prompt = buildPromptForGPT();
     const prompt = buildPromptForGPT();
     const res = await fetch('/dashboard/api/openai_project_gpt.php', {
    logActivity('🤖 Analisi GPT via proxy – modello: <b>'+model+'</b>');
       method:'POST', headers:{'Content-Type':'application/json'}, credentials:'include',
 
       body: JSON.stringify({ prompt, model: (document.getElementById('model-select')?.value || 'gpt-4o-2024-05-13') })
     const r = await fetch('/dashboard/api/openai_project_gpt.php', {
       method:'POST',
      headers:{'Content-Type':'application/json'},
      credentials:'include',
       body: JSON.stringify({ model, prompt })
    });
    const j = await r.json();
    if (j.status==='ok' && j.result){
      renderGpt(j.result);
      logActivity('✅ Analisi GPT completata');
    }else{
      renderGpt('❌ Errore: ' + (j.error||'risposta vuota'));
      logActivity('❌ Errore GPT: ' + (j.error||'vuota'));
    }
  }catch(e){
    renderGpt('❌ Errore rete: '+e.message);
  }finally{
    btn.disabled=false; btn.textContent='Analizza con GPT';
  }
}
 
/* ---------- API progetto ---------- */
const API = {
  list:  '/dashboard/api/project_list.php',
  create: '/dashboard/api/project_create.php',
  del:    '/dashboard/api/project_delete.php',
  backup: '/dashboard/api/project_backup.php'
};
 
let currentProject = null;
 
async function loadProjects(){
  const ul = document.getElementById('projectsList');
  if (!ul) return;
  ul.innerHTML = '<li class="muted">Carico…</li>';
  try{
    const r = await fetch(API.list, {credentials:'include', cache:'no-store'});
    const t = await r.text(); let j;
    try{ j = JSON.parse(t); }catch(_){ throw new Error('Risposta non-JSON'); }
    if(!j.ok) throw new Error(j.error||'Lista progetti fallita');
 
    ul.innerHTML = '';
    (j.projects||[]).forEach(p=>{
      const li = document.createElement('li');
      li.className = 'list-item';
      const name = document.createElement('strong');
      name.textContent = p.name;
      name.style.fontWeight = (p.name===currentProject?'800':'600');
 
      const actions = document.createElement('div'); actions.className='actions';
      const bOpen = document.createElement('button'); bOpen.className='btn'; bOpen.textContent='Apri';
      bOpen.onclick = ()=>{ currentProject = p.name; loadProjects(); logActivity('📁 Progetto selezionato: <b>'+p.name+'</b>'); };
 
      const bZip = document.createElement('button'); bZip.className='btn'; bZip.textContent='ZIP';
      bZip.title='Crea backup zip'; bZip.onclick = ()=>backupProject(p.name);
 
      const bDel = document.createElement('button'); bDel.className='btn danger'; bDel.textContent='🗑️';
      bDel.title='Sposta nel cestino'; bDel.onclick = ()=>deleteProject(p.name);
 
      actions.append(bOpen,bZip,bDel);
      li.append(name, actions);
      ul.appendChild(li);
     });
     });
    const j = await res.json();
 
     if (j.status==='ok' && j.result) renderGpt(j.result);
     if(!j.projects || !j.projects.length){
    else renderGpt('❌ Errore: '+(j.error||'Risposta vuota'));
      ul.innerHTML = '<li class="muted">Nessun progetto presente.</li>';
   }catch(e){ renderGpt('Errore rete: '+e.message); }
    }
   finally{ btn.disabled=false; btn.textContent='Analizza con GPT'; }
   }catch(e){
    ul.innerHTML = '<li class="muted">Errore: '+e.message+'</li>';
   }
}
}


/* Crea progetto (usa API server già presenti) */
async function createProject(){
async function createProject(){
   const input = document.getElementById('newProjectName');
   const input = document.getElementById('newProjectName');
Riga 304: Riga 302:
   if (!name) return alert('Inserisci un nome progetto (A-Z 0-9 _ -)');
   if (!name) return alert('Inserisci un nome progetto (A-Z 0-9 _ -)');
   try{
   try{
     const body = new URLSearchParams({ name });
     const body = new URLSearchParams({name});
     const r = await fetch('/dashboard/api/project_create.php', {
     const r = await fetch(API.create,{method:'POST',body,credentials:'include'});
      method:'POST', body, credentials:'include'
    });
     const j = await r.json();
     const j = await r.json();
     if (!j.ok) throw new Error(j.error||'create failed');
     if(!j.ok) throw new Error(j.error||'create failed');
     input.value='';
     input.value=''; currentProject = name;
    await loadProjects();
     logActivity('📁 Creato progetto: <b>'+name+'</b>');
     alert('✅ Progetto creato: '+name);
    loadProjects();
   }catch(e){ alert('Errore creazione: '+e.message); }
   }catch(e){ alert('Errore creazione: '+e.message); }
}
}


/* Lista e rendering progetti */
async function deleteProject(name){
async function loadProjects(){
   if(!confirm('Spostare "'+name+'" nel cestino?')) return;
   const ul = document.getElementById('projectsList'); if (!ul) return;
  ul.innerHTML = '<em class="muted">Carico…</em>';
   try{
   try{
     const r = await fetch('/dashboard/api/project_list.php', {credentials:'include',cache:'no-store'});
    const body = new URLSearchParams({name});
     const r = await fetch(API.del,{method:'POST',body,credentials:'include'});
     const j = await r.json();
     const j = await r.json();
     if (!j.ok) throw new Error(j.error||'list failed');
     if(!j.ok) throw new Error(j.error||'delete failed');
    const items = (j.projects||[]).sort((a,b)=> (b.mtime||0)-(a.mtime||0));
     if(currentProject===name) currentProject=null;
     if (!items.length){ ul.innerHTML = '<em class="muted">Nessun progetto. Creane uno.</em>'; return; }
    logActivity('🗑️ Progetto nel cestino: <b>'+name+'</b>');
    ul.innerHTML = '';
    loadProjects();
    items.forEach(p=>{
   }catch(e){ alert('Errore eliminazione: '+e.message); }
      const li = document.createElement('li');
      li.style.display='flex'; li.style.alignItems='center'; li.style.gap='8px'; li.style.margin='6px 0';
      const label = document.createElement('span'); label.textContent = p.name; label.style.fontWeight='600';
      const open  = document.createElement('button'); open.textContent='Apri';
      open.onclick = ()=> alert('Selezionato: '+p.name+' (vista file arriverà dopo)');
      const zip  = document.createElement('button'); zip.textContent='ZIP'; zip.title='Crea backup zip';
      zip.onclick = async ()=>{
        const body = new URLSearchParams({ name: p.name });
        const rr = await fetch('/dashboard/api/project_backup.php', {method:'POST', body, credentials:'include'});
        const jj = await rr.json(); if (!jj.ok) return alert('❌ Errore backup: '+(jj.error||'')); alert('✅ Backup creato: '+jj.zip);
      };
      const del  = document.createElement('button'); del.textContent='🗑️'; del.title='Sposta nel cestino';
      del.onclick = async ()=>{
        if (!confirm('Spostare "'+p.name+'" nel cestino?')) return;
        const body = new URLSearchParams({ name: p.name });
        const rr = await fetch('/dashboard/api/project_delete.php', {method:'POST', body, credentials:'include'});
        const jj = await rr.json(); if (!jj.ok) return alert('❌ Errore eliminazione: '+(jj.error||'')); loadProjects();
      };
      li.append(label, open, zip, del);
      ul.appendChild(li);
    });
   }catch(e){ ul.innerHTML = '<span style="color:#c00">Errore: '+e.message+'</span>'; }
}
}


/* 📁 COPIA DAL SERVER → PROGETTO (SANIFICATO) */
async function backupProject(name){
async function copyFromServerSanitized(){
   try{
   const src      = (document.getElementById('sourcePathInput')?.value||'').trim();
    const body = new URLSearchParams({name});
  const project  = (document.getElementById('gpt-load-project')?.value||'').trim();
    const r = await fetch(API.backup,{method:'POST',body,credentials:'include'});
  const subfolder = (document.getElementById('gpt-load-subfolder')?.value||'php').trim() || 'php';
    const j = await r.json();
   const filename  = (document.getElementById('gpt-load-filename')?.value||'').trim();
    if(!j.ok) throw new Error(j.error||'backup failed');
    alert('Backup creato: '+j.zip);
    logActivity('🗜️ ZIP creato per <b>'+name+'</b>');
   }catch(e){ alert('Errore backup: '+e.message); }
}


  if (!src)     return alert('Inserisci il percorso assoluto del file sorgente (SERVER).');
/* ---------- test tools ---------- */
   if (!project) return alert('Inserisci il nome del progetto.');
function runTestCode(){
   if (!filename) return alert('Inserisci il Filename di destinazione.');
  const ta = document.getElementById('codeArea');
   if(!ta) return;
  try{ new Function(ta.value||'')(); }
   catch(e){ alert('Errore nel codice: '+e.message); }
}


   const destination = `${project}/${subfolder}/${filename}`;
/* ---------- checkCodeAI (usa ai_check.php) ---------- */
async function checkCodeAI(){
   const codeEl = document.getElementById('codeArea');
  const outEl  = document.getElementById('consoleOutput');
  if(!codeEl || !outEl){ alert('Manca #codeArea o #consoleOutput'); return; }
  const code = codeEl.value||'';
  if(!code.trim()) return alert('Incolla del codice da analizzare.');


  outEl.textContent = '⏳ Invio al correttore AI…';
   try{
   try{
     const r = await fetch('/dashboard/api/copy_file_from_path.php', {
     const r = await fetch('/dashboard/api/ai_check.php', {
       method:'POST', credentials:'include',
       method:'POST',
       headers:{'Content-Type':'application/json'},
       headers:{'Content-Type':'application/x-www-form-urlencoded;charset=UTF-8'},
       body: JSON.stringify({ source: src, destination, sanitize: 1 }) // << SANIFICA
       body:new URLSearchParams({language:'php', code})
     });
     });
     const txt = await r.text();
     const j = await r.json();
     let j; try{ j=JSON.parse(txt); }catch{ j={ok:false,error:'Risposta non-JSON',raw:txt}; }
     if(j.ok){
    if (j.ok){
      let txt=''; if(j.lint && j.lint.trim()) txt+='=== LINT ===\\n'+j.lint+'\\n\\n';
       alert('✅ Copiato (sanificato) in: '+(j.path||destination));
       txt+=(j.analysis||'Nessun output.');
     } else {
      outEl.textContent=txt;
       alert('❌ Errore copia: '+(j.error||'')+(j.raw?'\nRAW:\n'+j.raw.substring(0,400):''));
     }else{
       outEl.textContent='❌ Errore: '+(j.error||'sconosciuto');
      if(j.raw) outEl.textContent+='\\n\\nRAW:\\n'+j.raw;
     }
     }
   }catch(e){ alert('❌ Errore rete: '+e.message); }
   }catch(e){ outEl.textContent='❌ Errore rete: '+e.message; }
}
}


/* Lettura file salvato (verifica) */
/* ---------- connessione API test ---------- */
async function caricaFileGPT(){
async function testAPIConnection(){
   const project  = (document.getElementById('gpt-load-project')?.value||'').trim();
   const prompt = (document.getElementById('test-prompt')?.value||'').trim();
   const subfolder = (document.getElementById('gpt-load-subfolder')?.value||'php').trim()||'php';
   const model  = document.getElementById('model-select')?.value || 'gpt-4o-2024-05-13';
   const filename  = (document.getElementById('gpt-load-filename')?.value||'').trim();
   const out    = document.getElementById('api-result');
   if (!project || !filename) return alert('Compila Project e Filename');
   if(!prompt){ out.textContent='⚠️ Inserisci un prompt di test.'; return; }
 
  out.textContent='⏳ Contatto il proxy sul server…';
   try{
   try{
     const url = `/dashboard/api/read_file.php?projectName=${encodeURIComponent(project)}&subfolder=${encodeURIComponent(subfolder)}&filename=${encodeURIComponent(filename)}`;
     const res = await fetch('/dashboard/api/openai_project_gpt.php', {
    const r = await fetch(url, {credentials:'include',cache:'no-store'});
      method:'POST',
     const j = await r.json();
      headers:{'Content-Type':'application/json'},
     if (j.status==='ok'){
      credentials:'include',
       renderGpt('```\n'+(j.content||'')+'\n```');
      body: JSON.stringify({ prompt, model })
     } else {
    });
       alert('❌ Errore lettura: '+(j.error||''));
     const data = await res.json();
     if (data.status==='ok' && data.result){
       out.textContent = '✅ Risposta: ' + data.result;
      logActivity('✅ Proxy OK – modello '+model);
     }else{
       out.textContent = '❌ Errore: ' + (data.error||'risposta vuota');
     }
     }
   }catch(e){ alert('Errore rete: '+e.message); }
   }catch(e){ out.textContent='🚫 Errore di rete: '+e.message; }
}
}


/* Bind iniziali */
/* ---------- init ---------- */
document.addEventListener('DOMContentLoaded', ()=>{
document.addEventListener('DOMContentLoaded', ()=>{
  // mostra subito Stato Progetti
  showBox('project-status');
  // bind
   document.getElementById('btnAnalyze')?.addEventListener('click', runProjectAnalysis);
   document.getElementById('btnAnalyze')?.addEventListener('click', runProjectAnalysis);
   document.getElementById('btnCreateProject')?.addEventListener('click', createProject);
   document.getElementById('btnCreateProject')?.addEventListener('click', createProject);
  // carica lista progetti
   loadProjects();
   loadProjects();
});
});
</script>
</script>
<script>
document.addEventListener('DOMContentLoaded', () => {
  // tieni la sezione sempre aperta
  const ps = document.getElementById('project-status');
  if (ps) ps.style.display = 'block';
  // bind pulsanti
  document.getElementById('btnAnalyze')?.addEventListener('click', runProjectAnalysis);
  document.getElementById('btnCreateProject')?.addEventListener('click', createProject);
  // popola lista progetti
  loadProjects();
});
</script>


</body>
</body>
</html>
</html>

Versione delle 10:57, 21 set 2025

Dashboard Operativa – Masticationpedia

🔧 Dashboard Operativa – Masticationpedia

Centro di comando per progetti, API, file e backup

🧾 Apri Log Dashboard
📊 Stato Progetti
Qui apparirà la risposta generata da GPT sull’analisi del progetto…
usa /dashboard/api/openai_project_gpt.php

📂 Gestione Progetti