This commit is contained in:
Raven Scott
2025-11-24 17:05:20 -05:00
parent 0cf2df3c76
commit 07cdbf293e
3 changed files with 2154 additions and 48 deletions
+677 -25
View File
@@ -13,28 +13,31 @@
<!-- xterm.css for Terminal -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm/css/xterm.css">
<!-- Chart.js for Stats Visualization -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/chart.umd.min.js"></script>
<style>
/* Modern CSS Variables for Theme */
/* Modern CSS Variables for Theme - Portainer-inspired */
:root {
/* Color Palette - Modern Dark Theme */
--bg-primary: #0f0f23;
--bg-secondary: #1a1a2e;
--bg-tertiary: #16213e;
--bg-elevated: #1e2749;
--bg-hover: #2a2d52;
/* Color Palette - Portainer-inspired Dark Theme */
--bg-primary: #1e1e2e;
--bg-secondary: #252936;
--bg-tertiary: #2d3142;
--bg-elevated: #353a4f;
--bg-hover: #3d4258;
/* Accent Colors */
--accent-primary: #6366f1;
--accent-secondary: #8b5cf6;
--accent-success: #10b981;
--accent-warning: #f59e0b;
--accent-danger: #ef4444;
--accent-info: #3b82f6;
/* Accent Colors - Portainer Blue Theme */
--accent-primary: #4dabf7;
--accent-secondary: #339af0;
--accent-success: #51cf66;
--accent-warning: #ffd43b;
--accent-danger: #ff6b6b;
--accent-info: #74c0fc;
/* Text Colors */
--text-primary: #ffffff;
--text-secondary: #a1a1aa;
--text-muted: #71717a;
--text-primary: #e9ecef;
--text-secondary: #adb5bd;
--text-muted: #6c757d;
/* Border & Divider */
--border-color: rgba(255, 255, 255, 0.1);
@@ -71,9 +74,10 @@
background: linear-gradient(135deg, var(--bg-primary) 0%, var(--bg-secondary) 100%);
color: var(--text-primary);
overflow: hidden;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', sans-serif;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Inter', sans-serif;
font-size: 14px;
line-height: 1.6;
line-height: 1.65;
font-weight: 400;
}
.hidden {
@@ -344,6 +348,175 @@
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);
}
/* Navigation Menu */
.nav-menu {
list-style: none;
padding: 0;
margin: 0 0 var(--spacing-lg) 0;
}
.nav-item {
margin-bottom: var(--spacing-xs);
}
.nav-link {
display: flex;
align-items: center;
gap: var(--spacing-md);
padding: var(--spacing-md);
color: var(--text-secondary);
text-decoration: none;
border-radius: var(--border-radius-sm);
transition: all var(--transition-fast);
font-weight: 500;
}
.nav-link:hover {
background: var(--bg-hover);
color: var(--text-primary);
transform: translateX(4px);
}
.nav-link.active {
background: linear-gradient(90deg, rgba(99, 102, 241, 0.2) 0%, rgba(99, 102, 241, 0.1) 100%);
color: var(--accent-primary);
border-left: 3px solid var(--accent-primary);
}
.nav-link i {
width: 20px;
text-align: center;
font-size: 1rem;
}
.nav-label {
flex: 1;
}
.sidebar-divider {
border-color: var(--border-color);
margin: var(--spacing-md) 0;
opacity: 0.3;
}
#sidebar.collapsed .nav-label {
display: none;
}
#sidebar.collapsed .nav-link {
justify-content: center;
padding: var(--spacing-md);
}
/* View Management */
.view {
display: flex;
flex-direction: column;
flex: 1;
width: 100%;
margin-top: 35px;
overflow-y: auto;
position: relative;
padding: var(--spacing-lg);
}
.view.hidden {
display: none !important;
}
/* Dashboard Styles */
.stat-card {
background: var(--bg-elevated);
border: 1px solid var(--border-color);
border-radius: var(--border-radius);
padding: var(--spacing-lg);
display: flex;
align-items: center;
gap: var(--spacing-md);
transition: all var(--transition-fast);
}
.stat-card:hover {
transform: translateY(-2px);
box-shadow: var(--shadow-lg);
border-color: var(--accent-primary);
}
.stat-card-icon {
width: 56px;
height: 56px;
border-radius: var(--border-radius-sm);
display: flex;
align-items: center;
justify-content: center;
font-size: 1.5rem;
flex-shrink: 0;
}
.stat-card-content {
flex: 1;
}
.stat-card-value {
font-size: 2rem;
font-weight: 700;
color: var(--text-primary);
line-height: 1;
margin-bottom: var(--spacing-xs);
}
.stat-card-label {
font-size: 0.875rem;
color: var(--text-secondary);
text-transform: uppercase;
letter-spacing: 0.05em;
}
.info-card {
background: var(--bg-elevated);
border: 1px solid var(--border-color);
border-radius: var(--border-radius);
padding: var(--spacing-lg);
transition: all var(--transition-fast);
}
.info-card:hover {
box-shadow: var(--shadow-md);
}
.info-card-title {
color: var(--text-primary);
font-weight: 600;
font-size: 1.125rem;
margin-bottom: var(--spacing-md);
padding-bottom: var(--spacing-md);
border-bottom: 1px solid var(--border-color);
}
.info-card-body {
color: var(--text-secondary);
}
.info-card-body .key-value {
display: flex;
justify-content: space-between;
padding: var(--spacing-sm) 0;
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}
.info-card-body .key-value:last-child {
border-bottom: none;
}
.info-card-body .key {
font-weight: 600;
color: var(--text-primary);
}
.info-card-body .value {
color: var(--text-secondary);
}
/* Connection Name Styling */
.connection-name {
font-weight: 600;
@@ -889,7 +1062,7 @@
}
.notification-tray {
/* Position is now relative, no top/right needed */
position: relative;
}
.notification-tray-toggle {
@@ -1376,14 +1549,16 @@
}
.btn-primary {
background: linear-gradient(135deg, var(--accent-primary) 0%, var(--accent-secondary) 100%);
background: var(--accent-primary);
border-color: var(--accent-primary);
color: var(--text-primary);
color: #ffffff;
font-weight: 500;
}
.btn-primary:hover {
background: linear-gradient(135deg, var(--accent-secondary) 0%, var(--accent-primary) 100%);
box-shadow: 0 4px 12px rgba(99, 102, 241, 0.4);
background: var(--accent-secondary);
border-color: var(--accent-secondary);
box-shadow: 0 4px 12px rgba(77, 171, 247, 0.4);
}
.btn-outline-success {
@@ -1720,6 +1895,44 @@
<div id="sidebar">
<button id="collapse-sidebar-btn">&lt;</button>
<div class="content">
<!-- Navigation Menu -->
<nav id="main-nav" class="mb-3">
<ul class="nav-menu">
<li class="nav-item">
<a href="#" class="nav-link active" data-view="dashboard">
<i class="fas fa-tachometer-alt"></i>
<span class="nav-label">Dashboard</span>
</a>
</li>
<li class="nav-item">
<a href="#" class="nav-link" data-view="containers">
<i class="fas fa-box"></i>
<span class="nav-label">Containers</span>
</a>
</li>
<li class="nav-item">
<a href="#" class="nav-link" data-view="images">
<i class="fas fa-images"></i>
<span class="nav-label">Images</span>
</a>
</li>
<li class="nav-item">
<a href="#" class="nav-link" data-view="networks">
<i class="fas fa-network-wired"></i>
<span class="nav-label">Networks</span>
</a>
</li>
<li class="nav-item">
<a href="#" class="nav-link" data-view="volumes">
<i class="fas fa-database"></i>
<span class="nav-label">Volumes</span>
</a>
</li>
</ul>
</nav>
<hr class="sidebar-divider">
<h4 class="text-center mt-3">Connections</h4>
<ul id="connection-list" class="list-group mb-3"></ul>
<form id="add-connection-form" class="px-3 d-flex align-items-center">
@@ -1739,7 +1952,110 @@
<p>To get started, add a connection using the form in the sidebar.</p>
<!-- <img src="https://via.placeholder.com/500x300" alt="Welcome Graphic" class="img-fluid mt-4"> -->
</div>
<div id="dashboard" class="hidden">
<!-- Dashboard View -->
<div id="dashboard-view" class="view hidden">
<div class="container-fluid">
<h2 class="mb-4"><i class="fas fa-tachometer-alt me-2"></i>Dashboard</h2>
<!-- System Overview Cards -->
<div class="row g-3 mb-4">
<div class="col-md-3">
<div class="stat-card">
<div class="stat-card-icon" style="background: rgba(16, 185, 129, 0.2); color: var(--accent-success);">
<i class="fas fa-box"></i>
</div>
<div class="stat-card-content">
<div class="stat-card-value" id="stat-running-containers">0</div>
<div class="stat-card-label">Running Containers</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="stat-card">
<div class="stat-card-icon" style="background: rgba(239, 68, 68, 0.2); color: var(--accent-danger);">
<i class="fas fa-stop-circle"></i>
</div>
<div class="stat-card-content">
<div class="stat-card-value" id="stat-stopped-containers">0</div>
<div class="stat-card-label">Stopped Containers</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="stat-card">
<div class="stat-card-icon" style="background: rgba(59, 130, 246, 0.2); color: var(--accent-info);">
<i class="fas fa-images"></i>
</div>
<div class="stat-card-content">
<div class="stat-card-value" id="stat-total-images">0</div>
<div class="stat-card-label">Total Images</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="stat-card">
<div class="stat-card-icon" style="background: rgba(139, 92, 246, 0.2); color: var(--accent-secondary);">
<i class="fas fa-network-wired"></i>
</div>
<div class="stat-card-content">
<div class="stat-card-value" id="stat-total-networks">0</div>
<div class="stat-card-label">Networks</div>
</div>
</div>
</div>
</div>
<!-- System Information -->
<div class="row g-3 mb-4">
<div class="col-md-6">
<div class="info-card">
<h5 class="info-card-title"><i class="fas fa-info-circle me-2"></i>Docker Information</h5>
<div id="docker-info-content" class="info-card-body">
<div class="skeleton skeleton-text"></div>
<div class="skeleton skeleton-text mt-2"></div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="info-card">
<h5 class="info-card-title"><i class="fas fa-server me-2"></i>System Resources</h5>
<div id="system-resources-content" class="info-card-body">
<div class="skeleton skeleton-text"></div>
<div class="skeleton skeleton-text mt-2"></div>
</div>
</div>
</div>
</div>
<!-- Quick Actions -->
<div class="row g-3">
<div class="col-12">
<div class="info-card">
<h5 class="info-card-title"><i class="fas fa-bolt me-2"></i>Quick Actions</h5>
<div class="info-card-body">
<div class="d-flex gap-2 flex-wrap">
<button class="btn btn-primary" onclick="window.navigateToView('containers')">
<i class="fas fa-box me-2"></i>View Containers
</button>
<button class="btn btn-outline-primary" onclick="window.navigateToView('images')">
<i class="fas fa-images me-2"></i>Manage Images
</button>
<button class="btn btn-outline-primary" onclick="window.navigateToView('networks')">
<i class="fas fa-network-wired me-2"></i>Manage Networks
</button>
<button class="btn btn-outline-primary" onclick="window.navigateToView('volumes')">
<i class="fas fa-database me-2"></i>Manage Volumes
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Containers View -->
<div id="containers-view" class="view hidden">
<!-- Container Filter and Search -->
<div class="container-fluid mb-3 mt-3">
<div class="row g-2">
@@ -1808,10 +2124,36 @@
</div>
</div>
</div>
<!-- Bulk Actions Toolbar -->
<div id="bulk-actions-toolbar" class="mb-3 p-3 bg-dark border rounded" style="display: none;">
<div class="d-flex align-items-center justify-content-between">
<div>
<span id="selected-count" class="text-primary fw-bold">0</span>
<span class="text-secondary"> container(s) selected</span>
</div>
<div class="btn-group">
<button class="btn btn-sm btn-outline-success" onclick="bulkStartContainers()" title="Start Selected">
<i class="fas fa-play me-1"></i>Start
</button>
<button class="btn btn-sm btn-outline-warning" onclick="bulkStopContainers()" title="Stop Selected">
<i class="fas fa-stop me-1"></i>Stop
</button>
<button class="btn btn-sm btn-outline-danger" onclick="bulkRemoveContainers()" title="Remove Selected">
<i class="fas fa-trash me-1"></i>Remove
</button>
<button class="btn btn-sm btn-outline-secondary" onclick="clearContainerSelection()" title="Clear Selection">
<i class="fas fa-times me-1"></i>Clear
</button>
</div>
</div>
</div>
<div class="table-responsive">
<table class="table table-dark table-striped">
<thead>
<tr>
<th style="width: 40px;">
<input type="checkbox" id="select-all-containers" onchange="toggleSelectAllContainers(this)">
</th>
<th>Name</th>
<th>Image</th>
<th>Status</th>
@@ -1825,6 +2167,218 @@
</table>
</div>
</div>
<!-- Images View -->
<div id="images-view" class="view hidden">
<div class="container-fluid">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2><i class="fas fa-images me-2"></i>Images</h2>
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#pullImageModal">
<i class="fas fa-download me-2"></i>Pull Image
</button>
</div>
<!-- Bulk Actions Toolbar for Images -->
<div id="bulk-actions-images-toolbar" class="mb-3 p-3 bg-dark border rounded" style="display: none;">
<div class="d-flex align-items-center justify-content-between">
<div>
<span id="selected-images-count" class="text-primary fw-bold">0</span>
<span class="text-secondary"> image(s) selected</span>
</div>
<div class="btn-group">
<button class="btn btn-sm btn-outline-danger" onclick="bulkRemoveImages()" title="Remove Selected">
<i class="fas fa-trash me-1"></i>Remove
</button>
<button class="btn btn-sm btn-outline-secondary" onclick="clearImageSelection()" title="Clear Selection">
<i class="fas fa-times me-1"></i>Clear
</button>
</div>
</div>
</div>
<div class="table-responsive">
<table class="table table-dark table-striped">
<thead>
<tr>
<th style="width: 40px;">
<input type="checkbox" id="select-all-images" onchange="toggleSelectAllImages(this)">
</th>
<th>Repository</th>
<th>Tag</th>
<th>Image ID</th>
<th>Size</th>
<th>Created</th>
<th>Usage</th>
<th>Actions</th>
</tr>
</thead>
<tbody id="images-list"></tbody>
</table>
</div>
</div>
</div>
<!-- Networks View -->
<div id="networks-view" class="view hidden">
<div class="container-fluid">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2><i class="fas fa-network-wired me-2"></i>Networks</h2>
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#createNetworkModal">
<i class="fas fa-plus me-2"></i>Create Network
</button>
</div>
<div class="table-responsive">
<table class="table table-dark table-striped">
<thead>
<tr>
<th>Name</th>
<th>Driver</th>
<th>Scope</th>
<th>Subnet</th>
<th>Gateway</th>
<th>Containers</th>
<th>Actions</th>
</tr>
</thead>
<tbody id="networks-list"></tbody>
</table>
</div>
</div>
</div>
<!-- Container Details View -->
<div id="container-details-view" class="view hidden">
<div class="container-fluid">
<div class="d-flex align-items-center mb-4">
<button class="btn btn-outline-secondary me-3" onclick="navigateToView('containers')">
<i class="fas fa-arrow-left me-2"></i>Back to Containers
</button>
<h2 class="mb-0" id="container-details-title">
<i class="fas fa-box me-2"></i>Container Details
</h2>
</div>
<!-- Container Details Tabs -->
<ul class="nav nav-tabs mb-4" id="container-details-tabs" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="overview-tab" data-bs-toggle="tab" data-bs-target="#overview-pane" type="button" role="tab">
<i class="fas fa-info-circle me-2"></i>Overview
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="logs-tab" data-bs-toggle="tab" data-bs-target="#logs-pane" type="button" role="tab">
<i class="fas fa-list-alt me-2"></i>Logs
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="stats-tab" data-bs-toggle="tab" data-bs-target="#stats-pane" type="button" role="tab">
<i class="fas fa-chart-line me-2"></i>Stats
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="config-tab" data-bs-toggle="tab" data-bs-target="#config-pane" type="button" role="tab">
<i class="fas fa-cog me-2"></i>Configuration
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="networking-tab" data-bs-toggle="tab" data-bs-target="#networking-pane" type="button" role="tab">
<i class="fas fa-network-wired me-2"></i>Networking
</button>
</li>
</ul>
<!-- Tab Content -->
<div class="tab-content" id="container-details-tab-content">
<!-- Overview Pane -->
<div class="tab-pane fade show active" id="overview-pane" role="tabpanel">
<div id="container-overview-content" class="info-card">
<div class="skeleton skeleton-text"></div>
<div class="skeleton skeleton-text mt-2"></div>
</div>
</div>
<!-- Logs Pane -->
<div class="tab-pane fade" id="logs-pane" role="tabpanel">
<div id="container-logs-content" class="info-card" style="max-height: 600px; overflow-y: auto; font-family: monospace; font-size: 0.875rem;">
<div class="text-muted text-center">Loading logs...</div>
</div>
</div>
<!-- Stats Pane -->
<div class="tab-pane fade" id="stats-pane" role="tabpanel">
<div id="container-stats-content" class="info-card">
<div class="row g-3">
<div class="col-md-6">
<div class="stat-card">
<div class="stat-card-icon" style="background: rgba(16, 185, 129, 0.2); color: var(--accent-success);">
<i class="fas fa-microchip"></i>
</div>
<div class="stat-card-content">
<div class="stat-card-value" id="detail-cpu">0%</div>
<div class="stat-card-label">CPU Usage</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="stat-card">
<div class="stat-card-icon" style="background: rgba(59, 130, 246, 0.2); color: var(--accent-info);">
<i class="fas fa-memory"></i>
</div>
<div class="stat-card-content">
<div class="stat-card-value" id="detail-memory">0 MB</div>
<div class="stat-card-label">Memory Usage</div>
</div>
</div>
</div>
</div>
<div id="stats-charts-container" class="mt-4">
<p class="text-muted">Stats charts will be displayed here</p>
</div>
</div>
</div>
<!-- Configuration Pane -->
<div class="tab-pane fade" id="config-pane" role="tabpanel">
<div id="container-config-content" class="info-card">
<div class="skeleton skeleton-text"></div>
<div class="skeleton skeleton-text mt-2"></div>
</div>
</div>
<!-- Networking Pane -->
<div class="tab-pane fade" id="networking-pane" role="tabpanel">
<div id="container-networking-content" class="info-card">
<div class="skeleton skeleton-text"></div>
<div class="skeleton skeleton-text mt-2"></div>
</div>
</div>
</div>
</div>
</div>
<!-- Volumes View -->
<div id="volumes-view" class="view hidden">
<div class="container-fluid">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2><i class="fas fa-database me-2"></i>Volumes</h2>
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#createVolumeModal">
<i class="fas fa-plus me-2"></i>Create Volume
</button>
</div>
<div class="table-responsive">
<table class="table table-dark table-striped">
<thead>
<tr>
<th>Name</th>
<th>Driver</th>
<th>Mountpoint</th>
<th>Usage</th>
<th>Actions</th>
</tr>
</thead>
<tbody id="volumes-list"></tbody>
</table>
</div>
</div>
</div>
</div>
@@ -2990,6 +3544,104 @@
</div>
</div>
<!-- Pull Image Modal -->
<div class="modal fade" id="pullImageModal" tabindex="-1" aria-labelledby="pullImageModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content bg-dark text-white">
<div class="modal-header">
<h5 class="modal-title" id="pullImageModalLabel"><i class="fas fa-download me-2"></i>Pull Image</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form id="pull-image-form">
<div class="mb-3">
<label for="pull-image-name" class="form-label">Image Name</label>
<input type="text" id="pull-image-name" class="form-control bg-dark text-white" placeholder="nginx:latest" required>
<small class="text-muted">Enter the full image name with tag (e.g., nginx:latest, ubuntu:20.04)</small>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" onclick="pullImage()">
<i class="fas fa-download me-2"></i>Pull Image
</button>
</div>
</div>
</div>
</div>
<!-- Create Network Modal -->
<div class="modal fade" id="createNetworkModal" tabindex="-1" aria-labelledby="createNetworkModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content bg-dark text-white">
<div class="modal-header">
<h5 class="modal-title" id="createNetworkModalLabel"><i class="fas fa-plus me-2"></i>Create Network</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form id="create-network-form">
<div class="mb-3">
<label for="network-name" class="form-label">Network Name</label>
<input type="text" id="network-name" class="form-control bg-dark text-white" placeholder="my-network" required>
</div>
<div class="mb-3">
<label for="network-driver" class="form-label">Driver</label>
<select id="network-driver" class="form-select bg-dark text-white">
<option value="bridge">Bridge</option>
<option value="overlay">Overlay</option>
<option value="macvlan">Macvlan</option>
<option value="host">Host</option>
</select>
</div>
<div class="mb-3">
<label for="network-subnet" class="form-label">Subnet (Optional)</label>
<input type="text" id="network-subnet" class="form-control bg-dark text-white" placeholder="172.20.0.0/16">
<small class="text-muted">CIDR notation (e.g., 172.20.0.0/16)</small>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" onclick="createNetwork()">
<i class="fas fa-plus me-2"></i>Create Network
</button>
</div>
</div>
</div>
</div>
<!-- Create Volume Modal -->
<div class="modal fade" id="createVolumeModal" tabindex="-1" aria-labelledby="createVolumeModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content bg-dark text-white">
<div class="modal-header">
<h5 class="modal-title" id="createVolumeModalLabel"><i class="fas fa-plus me-2"></i>Create Volume</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form id="create-volume-form">
<div class="mb-3">
<label for="volume-name" class="form-label">Volume Name</label>
<input type="text" id="volume-name" class="form-control bg-dark text-white" placeholder="my-volume" required>
</div>
<div class="mb-3">
<label for="volume-driver" class="form-label">Driver (Optional)</label>
<input type="text" id="volume-driver" class="form-control bg-dark text-white" placeholder="local">
<small class="text-muted">Leave empty for default local driver</small>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" onclick="createVolume()">
<i class="fas fa-plus me-2"></i>Create Volume
</button>
</div>
</div>
</div>
</div>
<!-- Legacy Alert Container (kept for backward compatibility, will be hidden) -->
<div id="alert-container" class="position-fixed top-0 start-50 translate-middle-x mt-3"
style="z-index: 1051; max-width: 90%; display: none;"></div>