Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Firely Server Deployment Dashboard</title> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| :root { | |
| --primary: #4a90e2; | |
| --primary-dark: #357abd; | |
| --secondary: #50c878; | |
| --danger: #e74c3c; | |
| --warning: #f39c12; | |
| --dark: #2c3e50; | |
| --darker: #1a252f; | |
| --light: #ecf0f1; | |
| --white: #ffffff; | |
| --gray: #95a5a6; | |
| --success: #27ae60; | |
| --info: #3498db; | |
| --border-radius: 12px; | |
| --transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); | |
| --shadow: 0 10px 40px rgba(0, 0, 0, 0.1); | |
| --shadow-lg: 0 20px 60px rgba(0, 0, 0, 0.15); | |
| } | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| } | |
| body { | |
| font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| min-height: 100vh; | |
| color: var(--dark); | |
| position: relative; | |
| } | |
| body::before { | |
| content: ''; | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| right: 0; | |
| bottom: 0; | |
| background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1440 320"><path fill="%23ffffff" fill-opacity="0.05" d="M0,96L48,112C96,128,192,160,288,165.3C384,171,480,149,576,138.7C672,128,768,128,864,138.7C960,149,1056,171,1152,165.3C1248,160,1344,128,1392,112L1440,96L1440,320L1392,320C1344,320,1248,320,1152,320C1056,320,960,320,864,320C768,320,672,320,576,320C480,320,384,320,288,320C192,320,96,320,48,320L0,320Z"></path></svg>') no-repeat bottom; | |
| background-size: cover; | |
| pointer-events: none; | |
| z-index: -1; | |
| } | |
| .container { | |
| max-width: 1400px; | |
| margin: 0 auto; | |
| padding: 20px; | |
| } | |
| header { | |
| background: rgba(255, 255, 255, 0.95); | |
| backdrop-filter: blur(10px); | |
| border-radius: var(--border-radius); | |
| padding: 30px; | |
| margin-bottom: 30px; | |
| box-shadow: var(--shadow); | |
| animation: slideDown 0.5s ease-out; | |
| } | |
| @keyframes slideDown { | |
| from { | |
| opacity: 0; | |
| transform: translateY(-20px); | |
| } | |
| to { | |
| opacity: 1; | |
| transform: translateY(0); | |
| } | |
| } | |
| .header-content { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| flex-wrap: wrap; | |
| gap: 20px; | |
| } | |
| .logo { | |
| display: flex; | |
| align-items: center; | |
| gap: 15px; | |
| } | |
| .logo i { | |
| font-size: 2.5rem; | |
| color: var(--primary); | |
| animation: pulse 2s infinite; | |
| } | |
| @keyframes pulse { | |
| 0%, 100% { transform: scale(1); } | |
| 50% { transform: scale(1.05); } | |
| } | |
| .logo h1 { | |
| font-size: 1.8rem; | |
| background: linear-gradient(135deg, var(--primary), var(--secondary)); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| } | |
| .status-indicators { | |
| display: flex; | |
| gap: 20px; | |
| align-items: center; | |
| } | |
| .status-badge { | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| padding: 8px 16px; | |
| background: var(--white); | |
| border-radius: 20px; | |
| box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); | |
| transition: var(--transition); | |
| } | |
| .status-badge:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15); | |
| } | |
| .status-dot { | |
| width: 10px; | |
| height: 10px; | |
| border-radius: 50%; | |
| animation: blink 2s infinite; | |
| } | |
| .status-dot.online { background: var(--success); } | |
| .status-dot.offline { background: var(--danger); } | |
| .status-dot.warning { background: var(--warning); } | |
| @keyframes blink { | |
| 0%, 100% { opacity: 1; } | |
| 50% { opacity: 0.5; } | |
| } | |
| .main-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); | |
| gap: 20px; | |
| margin-bottom: 30px; | |
| } | |
| .card { | |
| background: rgba(255, 255, 255, 0.95); | |
| backdrop-filter: blur(10px); | |
| border-radius: var(--border-radius); | |
| padding: 25px; | |
| box-shadow: var(--shadow); | |
| transition: var(--transition); | |
| animation: fadeInUp 0.5s ease-out forwards; | |
| opacity: 0; | |
| } | |
| .card:nth-child(1) { animation-delay: 0.1s; } | |
| .card:nth-child(2) { animation-delay: 0.2s; } | |
| .card:nth-child(3) { animation-delay: 0.3s; } | |
| .card:nth-child(4) { animation-delay: 0.4s; } | |
| @keyframes fadeInUp { | |
| from { | |
| opacity: 0; | |
| transform: translateY(20px); | |
| } | |
| to { | |
| opacity: 1; | |
| transform: translateY(0); | |
| } | |
| } | |
| .card:hover { | |
| transform: translateY(-5px); | |
| box-shadow: var(--shadow-lg); | |
| } | |
| .card-header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| margin-bottom: 20px; | |
| padding-bottom: 15px; | |
| border-bottom: 2px solid var(--light); | |
| } | |
| .card-title { | |
| font-size: 1.2rem; | |
| font-weight: 600; | |
| color: var(--dark); | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| } | |
| .card-title i { | |
| color: var(--primary); | |
| } | |
| .metric-value { | |
| font-size: 2rem; | |
| font-weight: bold; | |
| color: var(--primary); | |
| margin: 10px 0; | |
| } | |
| .metric-label { | |
| color: var(--gray); | |
| font-size: 0.9rem; | |
| } | |
| .progress-bar { | |
| width: 100%; | |
| height: 8px; | |
| background: var(--light); | |
| border-radius: 4px; | |
| overflow: hidden; | |
| margin: 10px 0; | |
| } | |
| .progress-fill { | |
| height: 100%; | |
| background: linear-gradient(90deg, var(--primary), var(--secondary)); | |
| border-radius: 4px; | |
| transition: width 0.5s ease-out; | |
| } | |
| .deployment-form { | |
| background: rgba(255, 255, 255, 0.95); | |
| backdrop-filter: blur(10px); | |
| border-radius: var(--border-radius); | |
| padding: 30px; | |
| box-shadow: var(--shadow); | |
| margin-bottom: 30px; | |
| } | |
| .form-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); | |
| gap: 20px; | |
| margin-bottom: 20px; | |
| } | |
| .form-group { | |
| display: flex; | |
| flex-direction: column; | |
| } | |
| .form-label { | |
| font-weight: 600; | |
| margin-bottom: 8px; | |
| color: var(--dark); | |
| display: flex; | |
| align-items: center; | |
| gap: 5px; | |
| } | |
| .form-label i { | |
| font-size: 0.9rem; | |
| color: var(--gray); | |
| } | |
| .form-control { | |
| padding: 12px 15px; | |
| border: 2px solid var(--light); | |
| border-radius: 8px; | |
| font-size: 1rem; | |
| transition: var(--transition); | |
| background: var(--white); | |
| } | |
| .form-control:focus { | |
| outline: none; | |
| border-color: var(--primary); | |
| box-shadow: 0 0 0 3px rgba(74, 144, 226, 0.1); | |
| } | |
| .form-control.error { | |
| border-color: var(--danger); | |
| } | |
| .error-message { | |
| color: var(--danger); | |
| font-size: 0.85rem; | |
| margin-top: 5px; | |
| display: none; | |
| } | |
| .btn { | |
| padding: 12px 24px; | |
| border: none; | |
| border-radius: 8px; | |
| font-size: 1rem; | |
| font-weight: 600; | |
| cursor: pointer; | |
| transition: var(--transition); | |
| display: inline-flex; | |
| align-items: center; | |
| gap: 8px; | |
| } | |
| .btn-primary { | |
| background: linear-gradient(135deg, var(--primary), var(--primary-dark)); | |
| color: var(--white); | |
| } | |
| .btn-primary:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 10px 20px rgba(74, 144, 226, 0.3); | |
| } | |
| .btn-success { | |
| background: linear-gradient(135deg, var(--success), #229954); | |
| color: var(--white); | |
| } | |
| .btn-danger { | |
| background: linear-gradient(135deg, var(--danger), #c0392b); | |
| color: var(--white); | |
| } | |
| .btn:disabled { | |
| opacity: 0.5; | |
| cursor: not-allowed; | |
| } | |
| .tabs { | |
| display: flex; | |
| gap: 10px; | |
| margin-bottom: 20px; | |
| border-bottom: 2px solid var(--light); | |
| overflow-x: auto; | |
| } | |
| .tab { | |
| padding: 12px 20px; | |
| background: transparent; | |
| border: none; | |
| border-bottom: 3px solid transparent; | |
| color: var(--gray); | |
| font-weight: 600; | |
| cursor: pointer; | |
| transition: var(--transition); | |
| white-space: nowrap; | |
| } | |
| .tab:hover { | |
| color: var(--primary); | |
| } | |
| .tab.active { | |
| color: var(--primary); | |
| border-bottom-color: var(--primary); | |
| } | |
| .tab-content { | |
| display: none; | |
| animation: fadeIn 0.3s ease-out; | |
| } | |
| .tab-content.active { | |
| display: block; | |
| } | |
| @keyframes fadeIn { | |
| from { opacity: 0; } | |
| to { opacity: 1; } | |
| } | |
| .log-viewer { | |
| background: var(--darker); | |
| color: var(--light); | |
| padding: 20px; | |
| border-radius: 8px; | |
| font-family: 'Courier New', monospace; | |
| font-size: 0.9rem; | |
| max-height: 400px; | |
| overflow-y: auto; | |
| margin-top: 20px; | |
| } | |
| .log-entry { | |
| margin-bottom: 5px; | |
| padding: 5px; | |
| border-radius: 4px; | |
| transition: var(--transition); | |
| } | |
| .log-entry:hover { | |
| background: rgba(255, 255, 255, 0.05); | |
| } | |
| .log-timestamp { | |
| color: var(--gray); | |
| margin-right: 10px; | |
| } | |
| .log-level { | |
| padding: 2px 6px; | |
| border-radius: 4px; | |
| font-size: 0.8rem; | |
| font-weight: bold; | |
| margin-right: 10px; | |
| } | |
| .log-level.info { background: var(--info); } | |
| .log-level.success { background: var(--success); } | |
| .log-level.warning { background: var(--warning); } | |
| .log-level.error { background: var(--danger); } | |
| .health-check { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); | |
| gap: 15px; | |
| margin-top: 20px; | |
| } | |
| .health-item { | |
| padding: 15px; | |
| background: var(--light); | |
| border-radius: 8px; | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| transition: var(--transition); | |
| } | |
| .health-item:hover { | |
| transform: translateX(5px); | |
| } | |
| .health-icon { | |
| font-size: 1.5rem; | |
| } | |
| .health-icon.healthy { color: var(--success); } | |
| .health-icon.unhealthy { color: var(--danger); } | |
| .health-icon.checking { color: var(--warning); } | |
| .modal { | |
| display: none; | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| right: 0; | |
| bottom: 0; | |
| background: rgba(0, 0, 0, 0.5); | |
| backdrop-filter: blur(5px); | |
| z-index: 1000; | |
| animation: fadeIn 0.3s ease-out; | |
| } | |
| .modal.active { | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| } | |
| .modal-content { | |
| background: var(--white); | |
| border-radius: var(--border-radius); | |
| padding: 30px; | |
| max-width: 500px; | |
| width: 90%; | |
| max-height: 90vh; | |
| overflow-y: auto; | |
| animation: slideUp 0.3s ease-out; | |
| } | |
| @keyframes slideUp { | |
| from { | |
| opacity: 0; | |
| transform: translateY(20px); | |
| } | |
| to { | |
| opacity: 1; | |
| transform: translateY(0); | |
| } | |
| } | |
| .modal-header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| margin-bottom: 20px; | |
| } | |
| .modal-title { | |
| font-size: 1.5rem; | |
| font-weight: bold; | |
| } | |
| .modal-close { | |
| background: none; | |
| border: none; | |
| font-size: 1.5rem; | |
| cursor: pointer; | |
| color: var(--gray); | |
| transition: var(--transition); | |
| } | |
| .modal-close:hover { | |
| color: var(--danger); | |
| } | |
| .spinner { | |
| border: 3px solid var(--light); | |
| border-top: 3px solid var(--primary); | |
| border-radius: 50%; | |
| width: 40px; | |
| height: 40px; | |
| animation: spin 1s linear infinite; | |
| margin: 20px auto; | |
| } | |
| @keyframes spin { | |
| 0% { transform: rotate(0deg); } | |
| 100% { transform: rotate(360deg); } | |
| } | |
| .toast { | |
| position: fixed; | |
| bottom: 20px; | |
| right: 20px; | |
| padding: 15px 20px; | |
| background: var(--white); | |
| border-radius: 8px; | |
| box-shadow: var(--shadow); | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| transform: translateX(400px); | |
| transition: transform 0.3s ease-out; | |
| z-index: 2000; | |
| } | |
| .toast.show { | |
| transform: translateX(0); | |
| } | |
| .toast.success { border-left: 4px solid var(--success); } | |
| .toast.error { border-left: 4px solid var(--danger); } | |
| .toast.warning { border-left: 4px solid var(--warning); } | |
| .toast.info { border-left: 4px solid var(--info); } | |
| .chart-container { | |
| position: relative; | |
| height: 300px; | |
| margin-top: 20px; | |
| } | |
| .environment-selector { | |
| display: flex; | |
| gap: 10px; | |
| margin-bottom: 20px; | |
| } | |
| .env-btn { | |
| padding: 10px 20px; | |
| border: 2px solid var(--light); | |
| background: var(--white); | |
| border-radius: 8px; | |
| cursor: pointer; | |
| transition: var(--transition); | |
| font-weight: 600; | |
| } | |
| .env-btn:hover { | |
| border-color: var(--primary); | |
| transform: translateY(-2px); | |
| } | |
| .env-btn.active { | |
| background: var(--primary); | |
| color: var(--white); | |
| border-color: var(--primary); | |
| } | |
| .secret-input { | |
| position: relative; | |
| } | |
| .secret-toggle { | |
| position: absolute; | |
| right: 10px; | |
| top: 50%; | |
| transform: translateY(-50%); | |
| background: none; | |
| border: none; | |
| color: var(--gray); | |
| cursor: pointer; | |
| } | |
| .deployment-history { | |
| margin-top: 20px; | |
| } | |
| .history-item { | |
| padding: 15px; | |
| background: var(--light); | |
| border-radius: 8px; | |
| margin-bottom: 10px; | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| transition: var(--transition); | |
| } | |
| .history-item:hover { | |
| background: #e8ecef; | |
| transform: translateX(5px); | |
| } | |
| .history-status { | |
| padding: 4px 12px; | |
| border-radius: 20px; | |
| font-size: 0.85rem; | |
| font-weight: 600; | |
| } | |
| .history-status.success { | |
| background: var(--success); | |
| color: var(--white); | |
| } | |
| .history-status.failed { | |
| background: var(--danger); | |
| color: var(--white); | |
| } | |
| .history-status.running { | |
| background: var(--warning); | |
| color: var(--white); | |
| } | |
| @media (max-width: 768px) { | |
| .container { | |
| padding: 10px; | |
| } | |
| .header-content { | |
| flex-direction: column; | |
| text-align: center; | |
| } | |
| .status-indicators { | |
| flex-wrap: wrap; | |
| justify-content: center; | |
| } | |
| .form-grid { | |
| grid-template-columns: 1fr; | |
| } | |
| .tabs { | |
| flex-wrap: nowrap; | |
| overflow-x: scroll; | |
| } | |
| .modal-content { | |
| padding: 20px; | |
| } | |
| } | |
| .footer { | |
| text-align: center; | |
| padding: 20px; | |
| color: var(--white); | |
| margin-top: 40px; | |
| } | |
| .footer a { | |
| color: var(--white); | |
| text-decoration: none; | |
| font-weight: 600; | |
| transition: var(--transition); | |
| } | |
| .footer a:hover { | |
| text-decoration: underline; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <header> | |
| <div class="header-content"> | |
| <div class="logo"> | |
| <i class="fas fa-server"></i> | |
| <h1>Firely Server Deployment Dashboard</h1> | |
| </div> | |
| <div class="status-indicators"> | |
| <div class="status-badge"> | |
| <span class="status-dot online"></span> | |
| <span>Docker: Online</span> | |
| </div> | |
| <div class="status-badge"> | |
| <span class="status-dot online"></span> | |
| <span>Environment: <span id="currentEnv">Dev</span></span> | |
| </div> | |
| <div class="status-badge"> | |
| <i class="fas fa-clock"></i> | |
| <span id="currentTime"></span> | |
| </div> | |
| </div> | |
| </div> | |
| </header> | |
| <div class="main-grid"> | |
| <div class="card"> | |
| <div class="card-header"> | |
| <div class="card-title"> | |
| <i class="fas fa-rocket"></i> | |
| Deployments | |
| </div> | |
| <span class="metric-value" id="deploymentCount">0</span> | |
| </div> | |
| <div class="metric-label">Total Deployments</div> | |
| <div class="progress-bar"> | |
| <div class="progress-fill" style="width: 75%"></div> | |
| </div> | |
| <div class="metric-label" style="margin-top: 10px;">Success Rate: 75%</div> | |
| </div> | |
| <div class="card"> | |
| <div class="card-header"> | |
| <div class="card-title"> | |
| <i class="fas fa-heartbeat"></i> | |
| Health Status | |
| </div> | |
| <i class="fas fa-check-circle" style="color: var(--success);"></i> | |
| </div> | |
| <div class="metric-value">100%</div> | |
| <div class="metric-label">Services Healthy</div> | |
| <div class="health-check"> | |
| <div class="health-item"> | |
| <i class="fas fa-database health-icon healthy"></i> | |
| <span>Database</span> | |
| </div> | |
| <div class="health-item"> | |
| <i class="fas fa-network-wired health-icon healthy"></i> | |
| <span>API</span> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="card"> | |
| <div class="card-header"> | |
| <div class="card-title"> | |
| <i class="fas fa-memory"></i> | |
| Resource Usage | |
| </div> | |
| <i class="fas fa-chart-line" style="color: var(--info);"></i> | |
| </div> | |
| <div class="metric-value">2.4 GB</div> | |
| <div class="metric-label">Memory Used</div> | |
| <div class="progress-bar"> | |
| <div class="progress-fill" style="width: 60%"></div> | |
| </div> | |
| <div class="metric-label" style="margin-top: 10px;">CPU: 45%</div> | |
| </div> | |
| <div class="card"> | |
| <div class="card-header"> | |
| <div class="card-title"> | |
| <i class="fas fa-shield-alt"></i> | |
| Security | |
| </div> | |
| <i class="fas fa-lock" style="color: var(--success);"></i> | |
| </div> | |
| <div class="metric-value">Enabled</div> | |
| <div class="metric-label">HTTPS Active</div> | |
| <div class="progress-bar"> | |
| <div class="progress-fill" style="width: 100%; background: var(--success)"></div> | |
| </div> | |
| <div class="metric-label" style="margin-top: 10px;">Certificate Valid</div> | |
| </div> | |
| </div> | |
| <div class="deployment-form"> | |
| <div class="card-header"> | |
| <div class="card-title"> | |
| <i class="fas fa-cogs"></i> | |
| Deployment Configuration | |
| </div> | |
| </div> | |
| <div class="environment-selector"> | |
| <button class="env-btn active" data-env="Dev"> | |
| <i class="fas fa-flask"></i> Development | |
| </button> | |
| <button class="env-btn" data-env="Test"> | |
| <i class="fas fa-vial"></i> Testing | |
| </button> | |
| <button class="env-btn" data-env="Prod"> | |
| <i class="fas fa-industry"></i> Production | |
| </button> | |
| </div> | |
| <form id="deploymentForm"> | |
| <div class="form-grid"> | |
| <div class="form-group"> | |
| <label class="form-label"> | |
| <i class="fas fa-file-contract"></i> | |
| License File Path | |
| </label> | |
| <input type="text" class="form-control" id="licensePath" | |
| placeholder="./config/licenses/firely-dev.lic" required> | |
| <span class="error-message">License file is required</span> | |
| </div> | |
| <div class="form-group"> | |
| <label class="form-label"> | |
| <i class="fas fa-folder"></i> | |
| Configuration Path | |
| </label> | |
| <input type="text" class="form-control" id="configPath" | |
| placeholder="./config/dev" required> | |
| <span class="error-message">Configuration path is required</span> | |
| </div> | |
| <div class="form-group"> | |
| <label class="form-label"> | |
| <i class="fas fa-plug"></i> | |
| HTTP Port | |
| </label> | |
| <input type="number" class="form-control" id="httpPort" | |
| value="8080" min="1" max="65535" required> | |
| <span class="error-message">Valid port required</span> | |
| </div> | |
| <div class="form-group"> | |
| <label class="form-label"> | |
| <i class="fas fa-lock"></i> | |
| HTTPS Port | |
| </label> | |
| <input type="number" class="form-control" id="httpsPort" | |
| value="8443" min="1" max="65535" required> | |
| <span class="error-message">Valid port required</span> | |
| </div> | |
| <div class="form-group"> | |
| <label class="form-label"> | |
| <i class="fas fa-fingerprint"></i> | |
| Certificate Thumbprint | |
| </label> | |
| <input type="text" class="form-control" id="certThumbprint" | |
| placeholder="Required for Production"> | |
| <span class="error-message">Certificate thumbprint required for Production</span> | |
| </div> | |
| <div class="form-group"> | |
| <label class="form-label"> | |
| <i class="fas fa-key"></i> | |
| Database Password Secret | |
| </label> | |
| <div class="secret-input"> | |
| <input type="password" class="form-control" id="dbPasswordSecret" | |
| placeholder="Secret name or value"> | |
| <button type="button" class="secret-toggle" onclick="toggleSecret('dbPasswordSecret')"> | |
| <i class="fas fa-eye"></i> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="form-group"> | |
| <label class="form-label"> | |
| <i class="fas fa-user-shield"></i> | |
| Auth Authority Secret | |
| </label> | |
| <div class="secret-input"> | |
| <input type="password" class="form-control" id="authAuthoritySecret" | |
| placeholder="Secret name or URL"> | |
| <button type="button" class="secret-toggle" onclick="toggleSecret('authAuthoritySecret')"> | |
| <i class="fas fa-eye"></i> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="form-group"> | |
| <label class="form-label"> | |
| <i class="fas fa-users"></i> | |
| Auth Audience Secret | |
| </label> | |
| <div class="secret-input"> | |
| <input type="password" class="form-control" id="authAudienceSecret" | |
| placeholder="Secret name or value"> | |
| <button type="button" class="secret-toggle" onclick="toggleSecret('authAudienceSecret')"> | |
| <i class="fas fa-eye"></i> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="form-group" style="flex-direction: row; gap: 20px; margin-top: 20px;"> | |
| <label style="display: flex; align-items: center; gap: 8px;"> | |
| <input type="checkbox" id="withMonitoring"> | |
| <span>Enable Monitoring Stack (Prometheus, Grafana)</span> | |
| </label> | |
| <label style="display: flex; align-items: center; gap: 8px;"> | |
| <input type="checkbox" id="withSecurity"> | |
| <span>Enable Enhanced Security</span> | |
| </label> | |
| <label style="display: flex; align-items: center; gap: 8px;"> | |
| <input type="checkbox" id="forceDeploy"> | |
| <span>Force Deployment (overwrite)</span> | |
| </label> | |
| </div> | |
| <div style="display: flex; gap: 10px; margin-top: 20px;"> | |
| <button type="submit" class="btn btn-primary"> | |
| <i class="fas fa-rocket"></i> | |
| Deploy Firely Server | |
| </button> | |
| <button type="button" class="btn btn-success" onclick="validateConfiguration()"> | |
| <i class="fas fa-check"></i> | |
| Validate Configuration | |
| </button> | |
| <button type="button" class="btn btn-danger" onclick="resetForm()"> | |
| <i class="fas fa-undo"></i> | |
| Reset | |
| </button> | |
| </div> | |
| </form> | |
| </div> | |
| <div class="card"> | |
| <div class="card-header"> | |
| <div class="card-title"> | |
| <i class="fas fa-tasks"></i> | |
| Deployment Operations | |
| </div> | |
| </div> | |
| <div class="tabs"> | |
| <button class="tab active" onclick="switchTab('logs')"> | |
| <i class="fas fa-file-alt"></i> Logs | |
| </button> | |
| <button class="tab" onclick="switchTab('monitoring')"> | |
| <i class="fas fa-chart-bar"></i> Monitoring | |
| </button> | |
| <button class="tab" onclick="switchTab('health')"> | |
| <i class="fas fa-heartbeat"></i> Health Checks | |
| </button> | |
| <button class="tab" onclick="switchTab('history')"> | |
| <i class="fas fa-history"></i> History | |
| </button> | |
| </div> | |
| <div id="logs" class="tab-content active"> | |
| <div class="log-viewer" id="logViewer"> | |
| <div class="log-entry"> | |
| <span class="log-timestamp">2024-01-15 10:30:45</span> | |
| <span class="log-level info">INFO</span> | |
| <span>Initializing Firely Server Deployment Dashboard...</span> | |
| </div> | |
| <div class="log-entry"> | |
| <span class="log-timestamp">2024-01-15 10:30:46</span> | |
| <span class="log-level success">SUCCESS</span> | |
| <span>Docker daemon connected successfully</span> | |
| </div> | |
| <div class="log-entry"> | |
| <span class="log-timestamp">2024-01-15 10:30:47</span> | |
| <span class="log-level info">INFO</span> | |
| <span>Loading environment configuration for Dev</span> | |
| </div> | |
| <div class="log-entry"> | |
| <span class="log-timestamp">2024-01-15 10:30:48</span> | |
| <span class="log-level success">SUCCESS</span> | |
| <span>All dependencies verified and ready</span> | |
| </div> | |
| </div> | |
| </div> | |
| <div id="monitoring" class="tab-content"> | |
| <div class="chart-container"> | |
| <canvas id="performanceChart"></canvas> | |
| </div> | |
| <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px; margin-top: 20px;"> | |
| <div class="health-item"> | |
| <i class="fas fa-tachometer-alt" style="color: var(--info);"></i> | |
| <div> | |
| <div>Response Time</div> | |
| <strong>45ms</strong> | |
| </div> | |
| </div> | |
| <div class="health-item"> | |
| <i class="fas fa-exchange-alt" style="color: var(--success);"></i> | |
| <div> | |
| <div>Requests/sec</div> | |
| <strong>234</strong> | |
| </div> | |
| </div> | |
| <div class="health-item"> | |
| <i class="fas fa-hdd" style="color: var(--warning);"></i> | |
| <div> | |
| <div>Disk Usage</div> | |
| <strong>67%</strong> | |
| </div> | |
| </div> | |
| <div class="health-item"> | |
| <i class="fas fa-network-wired" style="color: var(--primary);"></i> | |
| <div> | |
| <div>Network I/O</div> | |
| <strong>12 MB/s</strong> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div id="health" class="tab-content"> | |
| <div class="health-check"> | |
| <div class="health-item"> | |
| <i class="fas fa-database health-icon healthy"></i> | |
| <div> | |
| <div>PostgreSQL</div> | |
| <strong>Healthy</strong> | |
| </div> | |
| </div> | |
| <div class="health-item"> | |
| <i class="fas fa-server health-icon healthy"></i> | |
| <div> | |
| <div>Firely Server</div> | |
| <strong>Running</strong> | |
| </div> | |
| </div> | |
| <div class="health-item"> | |
| <i class="fas fa-chart-line health-icon healthy"></i> | |
| <div> | |
| <div>Prometheus</div> | |
| <strong>Active</strong> | |
| </div> | |
| </div> | |
| <div class="health-item"> | |
| <i class="fas fa-chart-pie health-icon healthy"></i> | |
| <div> | |
| <div>Grafana</div> | |
| <strong>Available</strong> | |
| </div> | |
| </div> | |
| <div class="health-item"> | |
| <i class="fas fa-lock health-icon healthy"></i> | |
| <div> | |
| <div>SSL Certificate</div> | |
| <strong>Valid</strong> | |
| </div> | |
| </div> | |
| <div class="health-item"> | |
| <i class="fas fa-memory health-icon checking"></i> | |
| <div> | |
| <div>Memory Check</div> | |
| <strong>Checking...</strong> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div id="history" class="tab-content"> | |
| <div class="deployment-history" id="deploymentHistory"> | |
| <div class="history-item"> | |
| <div> | |
| <strong>Deployment #1234</strong> | |
| <div style="color: var(--gray); font-size: 0.9rem;"> | |
| Environment: Prod | Time: 2024-01-15 09:15:30 | |
| </div> | |
| </div> | |
| <span class="history-status success">Success</span> | |
| </div> | |
| <div class="history-item"> | |
| <div> | |
| <strong>Deployment #1233</strong> | |
| <div style="color: var(--gray); font-size: 0.9rem;"> | |
| Environment: Test | Time: 2024-01-15 08:45:12 | |
| </div> | |
| </div> | |
| <span class="history-status success">Success</span> | |
| </div> | |
| <div class="history-item"> | |
| <div> | |
| <strong>Deployment #1232</strong> | |
| <div style="color: var(--gray); font-size: 0.9 |