index.html 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. <!DOCTYPE html>
  2. <html lang="es">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>VirtManager Dashboard</title>
  7. <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
  8. <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.css" rel="stylesheet">
  9. <style>
  10. * {
  11. margin: 0;
  12. padding: 0;
  13. box-sizing: border-box;
  14. }
  15. body {
  16. height: 100vh;
  17. overflow: hidden;
  18. background-color: #f8f9fa;
  19. }
  20. .dashboard-container {
  21. display: flex;
  22. height: 100vh;
  23. }
  24. /* Sidebar */
  25. .sidebar {
  26. width: 300px;
  27. background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  28. color: white;
  29. overflow-y: auto;
  30. box-shadow: 2px 0 5px rgba(0,0,0,0.1);
  31. display: flex;
  32. flex-direction: column;
  33. }
  34. .sidebar-header {
  35. padding: 20px;
  36. border-bottom: 1px solid rgba(255,255,255,0.2);
  37. flex-shrink: 0;
  38. }
  39. .sidebar-header h4 {
  40. margin: 0;
  41. font-weight: 600;
  42. font-size: 1.5rem;
  43. }
  44. .sidebar-header p {
  45. margin: 5px 0 0 0;
  46. font-size: 0.9rem;
  47. opacity: 0.9;
  48. }
  49. .sidebar-vms {
  50. flex: 1;
  51. overflow-y: auto;
  52. padding: 10px;
  53. }
  54. .vm-item {
  55. padding: 12px 15px;
  56. margin-bottom: 8px;
  57. background: rgba(255,255,255,0.15);
  58. border: 2px solid transparent;
  59. border-radius: 8px;
  60. cursor: pointer;
  61. transition: all 0.3s ease;
  62. display: flex;
  63. justify-content: space-between;
  64. align-items: center;
  65. }
  66. .vm-item:hover {
  67. background: rgba(255,255,255,0.25);
  68. transform: translateX(5px);
  69. }
  70. .vm-item.active {
  71. background: rgba(255,255,255,0.3);
  72. border-color: rgba(255,255,255,0.5);
  73. font-weight: 600;
  74. }
  75. .vm-item-name {
  76. flex: 1;
  77. }
  78. .vm-item-badge {
  79. font-size: 0.75rem;
  80. padding: 3px 8px;
  81. border-radius: 4px;
  82. }
  83. .sidebar-actions {
  84. padding: 15px;
  85. border-top: 1px solid rgba(255,255,255,0.2);
  86. flex-shrink: 0;
  87. display: flex;
  88. gap: 8px;
  89. }
  90. .sidebar-actions button {
  91. flex: 1;
  92. padding: 8px 12px;
  93. font-size: 0.9rem;
  94. }
  95. /* Main Content */
  96. .main-content {
  97. flex: 1;
  98. display: flex;
  99. flex-direction: column;
  100. overflow: hidden;
  101. }
  102. .top-bar {
  103. background: white;
  104. border-bottom: 1px solid #e9ecef;
  105. padding: 15px 25px;
  106. display: flex;
  107. justify-content: space-between;
  108. align-items: center;
  109. flex-shrink: 0;
  110. box-shadow: 0 2px 4px rgba(0,0,0,0.05);
  111. }
  112. .top-bar h2 {
  113. margin: 0;
  114. color: #333;
  115. }
  116. .content-area {
  117. flex: 1;
  118. overflow-y: auto;
  119. padding: 25px;
  120. }
  121. .empty-state {
  122. display: flex;
  123. flex-direction: column;
  124. justify-content: center;
  125. align-items: center;
  126. height: 100%;
  127. color: #999;
  128. text-align: center;
  129. }
  130. .empty-state i {
  131. font-size: 4rem;
  132. margin-bottom: 20px;
  133. opacity: 0.5;
  134. }
  135. .vm-details {
  136. display: grid;
  137. grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  138. gap: 20px;
  139. }
  140. .card {
  141. border: none;
  142. border-radius: 10px;
  143. box-shadow: 0 2px 8px rgba(0,0,0,0.08);
  144. transition: all 0.3s ease;
  145. }
  146. .card:hover {
  147. box-shadow: 0 4px 12px rgba(0,0,0,0.12);
  148. }
  149. .card-header {
  150. background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  151. color: white;
  152. border-radius: 10px 10px 0 0;
  153. padding: 15px;
  154. }
  155. .card-title {
  156. margin: 0;
  157. font-size: 1rem;
  158. }
  159. .badge-running {
  160. background-color: #28a745;
  161. }
  162. .badge-off {
  163. background-color: #6c757d;
  164. }
  165. .badge-paused {
  166. background-color: #ffc107;
  167. color: #333;
  168. }
  169. .badge-error {
  170. background-color: #dc3545;
  171. }
  172. .info-item {
  173. padding: 12px 0;
  174. border-bottom: 1px solid #e9ecef;
  175. }
  176. .info-item:last-child {
  177. border-bottom: none;
  178. }
  179. .info-label {
  180. font-weight: 600;
  181. color: #667eea;
  182. font-size: 0.9rem;
  183. }
  184. .info-value {
  185. color: #333;
  186. margin-top: 3px;
  187. }
  188. /* Tabs */
  189. .nav-tabs {
  190. border-bottom: 2px solid #e9ecef;
  191. margin-bottom: 20px;
  192. }
  193. .nav-tabs .nav-link {
  194. color: #667eea;
  195. border: none;
  196. border-bottom: 3px solid transparent;
  197. font-weight: 500;
  198. }
  199. .nav-tabs .nav-link:hover {
  200. border-bottom-color: #667eea;
  201. color: #764ba2;
  202. }
  203. .nav-tabs .nav-link.active {
  204. color: #764ba2;
  205. border-bottom-color: #764ba2;
  206. background: none;
  207. }
  208. /* Actions */
  209. .actions-group {
  210. margin-top: 20px;
  211. padding-top: 20px;
  212. border-top: 2px solid #e9ecef;
  213. }
  214. .actions-group h5 {
  215. color: #667eea;
  216. margin-bottom: 15px;
  217. }
  218. .btn-action {
  219. margin-right: 10px;
  220. margin-bottom: 10px;
  221. }
  222. @media (max-width: 768px) {
  223. .sidebar {
  224. width: 250px;
  225. }
  226. }
  227. </style>
  228. </head>
  229. <body>
  230. <div class="dashboard-container">
  231. <!-- Sidebar -->
  232. <div class="sidebar">
  233. <div class="sidebar-header">
  234. <h4><i class="bi bi-display"></i> VirtManager</h4>
  235. <p>Virtual Machine Dashboard</p>
  236. </div>
  237. <div class="sidebar-vms" id="vmList">
  238. <div class="text-center mt-3" style="color: rgba(255,255,255,0.7);">
  239. <p>Cargando máquinas...</p>
  240. </div>
  241. </div>
  242. <div class="sidebar-actions">
  243. <button class="btn btn-light btn-sm" onclick="loadVMs()" title="Actualizar">
  244. <i class="bi bi-arrow-clockwise"></i>
  245. </button>
  246. <button class="btn btn-light btn-sm" onclick="openCreateVMModal()" title="Nueva VM">
  247. <i class="bi bi-plus-circle"></i> Nueva
  248. </button>
  249. </div>
  250. </div>
  251. <!-- Main Content -->
  252. <div class="main-content">
  253. <div class="top-bar">
  254. <div>
  255. <h2 id="currentVMName">VirtManager</h2>
  256. </div>
  257. <div id="topBarActions">
  258. </div>
  259. </div>
  260. <div class="content-area" id="contentArea">
  261. <div class="empty-state">
  262. <i class="bi bi-inbox"></i>
  263. <h5>Selecciona una máquina virtual</h5>
  264. <p>Haz clic en una VM del panel lateral para ver sus detalles</p>
  265. </div>
  266. </div>
  267. </div>
  268. </div>
  269. <!-- Create VM Modal -->
  270. <div class="modal fade" id="createVMModal" tabindex="-1">
  271. <div class="modal-dialog">
  272. <div class="modal-content">
  273. <div class="modal-header">
  274. <h5 class="modal-title">Crear Nueva VM</h5>
  275. <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
  276. </div>
  277. <form id="createVMForm">
  278. <div class="modal-body">
  279. <div class="mb-3">
  280. <label for="name" class="form-label">Nombre</label>
  281. <input type="text" class="form-control" id="name" required>
  282. </div>
  283. <div class="mb-3">
  284. <label for="memory" class="form-label">Memoria (MiB)</label>
  285. <input type="number" class="form-control" id="memory" placeholder="2048" required>
  286. </div>
  287. <div class="mb-3">
  288. <label for="cpus" class="form-label">CPUs</label>
  289. <input type="number" class="form-control" id="cpus" value="1" min="1" required>
  290. </div>
  291. <div class="mb-3">
  292. <label for="disk_size" class="form-label">Tamaño de Disco (GB)</label>
  293. <input type="number" class="form-control" id="disk_size" placeholder="20" required>
  294. </div>
  295. <div class="mb-3">
  296. <label for="iso" class="form-label">Imagen ISO</label>
  297. <select class="form-control" id="iso" required>
  298. <option value="">Selecciona una ISO</option>
  299. </select>
  300. </div>
  301. </div>
  302. <div class="modal-footer">
  303. <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancelar</button>
  304. <button type="submit" class="btn btn-primary">Crear VM</button>
  305. </div>
  306. </form>
  307. </div>
  308. </div>
  309. </div>
  310. <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
  311. <script src="/static/dashboard.js"></script>
  312. </body>
  313. </html>