index.html 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>News MCP Dashboard</title>
  7. <link rel="stylesheet" href="/dashboard/style.css">
  8. <script src="https://cdn.jsdelivr.net/npm/htmx.org@1.9.12"></script>
  9. <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.4/dist/chart.umd.min.js"></script>
  10. </head>
  11. <body>
  12. <!-- TOP NAV -->
  13. <nav class="topnav">
  14. <div class="nav-brand">📡 news-mcp dashboard</div>
  15. <div class="nav-links">
  16. <a href="#" onclick="switchView('health'); return false;" class="active" data-view="health">Health</a>
  17. <a href="#" onclick="switchView('clusters'); return false;" data-view="clusters">Clusters</a>
  18. <a href="#" onclick="switchView('sentiment'); return false;" data-view="sentiment">Sentiment</a>
  19. <a href="#" onclick="switchView('entities'); return false;" data-view="entities">Entities</a>
  20. <a href="#" onclick="switchView('detail'); return false;" data-view="detail">Detail</a>
  21. </div>
  22. <div class="nav-meta" id="nav-meta"></div>
  23. </nav>
  24. <!-- HEALTH VIEW -->
  25. <div id="view-health" class="view active">
  26. <div class="card">
  27. <h3>📊 System Status</h3>
  28. <div id="health-stats" class="stat-grid">
  29. <div class="stat-box"><div class="label">Total Clusters</div><div class="value blue" id="stat-clusters">—</div></div>
  30. <div class="stat-box"><div class="label">Total Entities</div><div class="value blue" id="stat-entities">—</div></div>
  31. <div class="stat-box"><div class="label">Extracted Entities</div><div class="value blue" id="stat-cluster-entities">—</div></div>
  32. <div class="stat-box"><div class="label">Data Fresh</div><div class="value" id="stat-fresh">—</div></div>
  33. <div class="stat-box"><div class="label">Last Refresh</div><div class="value" style="font-size:1rem" id="stat-refresh">—</div></div>
  34. </div>
  35. </div>
  36. <div class="grid grid-3" style="margin-top:1rem">
  37. <div class="card">
  38. <h3>📋 Topics Distribution</h3>
  39. <div class="chart-wrap"><canvas id="chart-topic-dist"></canvas></div>
  40. </div>
  41. <div class="card">
  42. <h3>📈 Sentiment Over Time (4h buckets)</h3>
  43. <div class="chart-wrap"><canvas id="chart-sentiment-overview"></canvas></div>
  44. </div>
  45. <div class="card">
  46. <h3>🔗 Feed Activity</h3>
  47. <div id="feed-status"><div class="loading">Loading…</div></div>
  48. </div>
  49. </div>
  50. </div>
  51. <!-- CLUSTERS VIEW -->
  52. <div id="view-clusters" class="view">
  53. <div class="card">
  54. <div class="toolbar">
  55. <div class="filters">
  56. <select id="cluster-topic" onchange="reloadClusters()">
  57. <option value="all">All Topics</option>
  58. <option value="crypto">Crypto</option>
  59. <option value="macro">Macro</option>
  60. <option value="regulation">Regulation</option>
  61. <option value="ai">AI</option>
  62. <option value="other">Other</option>
  63. </select>
  64. <select id="cluster-hours" onchange="reloadClusters()">
  65. <option value="1">Last 1h</option>
  66. <option value="6">Last 6h</option>
  67. <option value="24">Last 24h</option>
  68. <option value="72">Last 3 days</option>
  69. <option value="168" selected>Last week</option>
  70. </select>
  71. <input type="text" id="cluster-search" placeholder="Search headlines…" onkeyup="filterClusters()" />
  72. <span class="badge" id="cluster-total">—</span>
  73. </div>
  74. </div>
  75. <div id="cluster-table"></div>
  76. </div>
  77. </div>
  78. <!-- SENTIMENT VIEW -->
  79. <div id="view-sentiment" class="view">
  80. <div class="card">
  81. <div class="toolbar">
  82. <div class="filters">
  83. <select id="sentiment-topic" onchange="reloadSentiment()">
  84. <option value="all">All Topics</option>
  85. <option value="crypto">Crypto</option>
  86. <option value="macro">Macro</option>
  87. <option value="regulation">Regulation</option>
  88. <option value="ai">AI</option>
  89. </select>
  90. <select id="sentiment-hours" onchange="reloadSentiment()">
  91. <option value="6">6h</option>
  92. <option value="144" selected>144h</option>
  93. <option value="72">72h</option>
  94. <option value="168">7d</option>
  95. </select>
  96. <select id="sentiment-bucket" onchange="reloadSentiment()">
  97. <option value="1">1h buckets</option>
  98. <option value="4" selected>4h buckets</option>
  99. <option value="12">12h buckets</option>
  100. </select>
  101. </div>
  102. </div>
  103. <div class="chart-wrap"><canvas id="chart-sentiment"></canvas></div>
  104. <div id="sentiment-stats" class="sentiment-stats"></div>
  105. </div>
  106. </div>
  107. <!-- ENTITIES VIEW -->
  108. <div id="view-entities" class="view">
  109. <div class="grid grid-3">
  110. <div class="card card-wide">
  111. <h3>🔗 Top Entities <small class="muted">(24h mentions)</small></h3>
  112. <div id="entity-list"><div class="loading">Loading…</div></div>
  113. </div>
  114. <div class="card">
  115. <h3>📊 Entity Frequency</h3>
  116. <div class="chart-wrap"><canvas id="chart-entities"></canvas></div>
  117. </div>
  118. <div class="card">
  119. <h3>ℹ️ Entity Detail</h3>
  120. <div id="entity-detail"><p class="muted">Click an entity in the list to see details.</p></div>
  121. </div>
  122. </div>
  123. </div>
  124. <!-- DETAIL VIEW -->
  125. <div id="view-detail" class="view">
  126. <div class="card">
  127. <div class="toolbar">
  128. <input type="text" id="detail-search" placeholder="Paste cluster_id or search…" />
  129. <button onclick="searchDetail()">🔍 Search</button>
  130. </div>
  131. <div id="detail-content"><p class="muted">Select a cluster from <a href="#" onclick="switchView('clusters'); return false;">Clusters</a> or search by cluster ID.</p></div>
  132. </div>
  133. </div>
  134. <!-- DETAIL MODAL (cluster drill-down) -->
  135. <div id="cluster-modal" class="modal-overlay" onclick="closeModal()">
  136. <div class="modal" onclick="event.stopPropagation()">
  137. <button class="modal-close" onclick="closeModal()">✕</button>
  138. <div id="modal-content"><div class="loading">Loading…</div></div>
  139. </div>
  140. </div>
  141. <div id="toast" class="toast"></div>
  142. <script src="/dashboard/dashboard.js"></script>
  143. </body>
  144. </html>