This commit is contained in:
@@ -13,30 +13,102 @@
|
||||
</head>
|
||||
|
||||
<body class="bg-slate-950 text-slate-100">
|
||||
<header class="border-b border-slate-800 bg-slate-950/80 backdrop-blur">
|
||||
<div class="mx-auto max-w-6xl px-4 py-3 flex items-center justify-between">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="h-9 w-9 rounded-lg bg-slate-800 flex items-center justify-center font-bold">A</div>
|
||||
<div>
|
||||
<div class="font-semibold leading-tight">AtlasOS</div>
|
||||
<div class="text-xs text-slate-400 leading-tight">Storage Controller v1</div>
|
||||
</div>
|
||||
<!-- Mobile Overlay -->
|
||||
<div id="mobile-overlay" class="fixed inset-0 bg-black/50 z-40 lg:hidden hidden" onclick="toggleSidebar()"></div>
|
||||
|
||||
<!-- Sidebar Navigation -->
|
||||
<aside id="sidebar" class="fixed left-0 top-0 h-full w-64 bg-slate-900 border-r border-slate-800 z-50 transform -translate-x-full lg:translate-x-0 transition-transform duration-300 ease-in-out flex flex-col">
|
||||
<!-- Logo/Brand -->
|
||||
<div class="p-4 border-b border-slate-800 flex items-center gap-3">
|
||||
<div class="h-10 w-10 rounded-lg bg-blue-600 flex items-center justify-center font-bold text-white">A</div>
|
||||
<div>
|
||||
<div class="font-semibold leading-tight text-white">AtlasOS</div>
|
||||
<div class="text-xs text-slate-400 leading-tight">Storage Controller v1</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="text-sm text-slate-300 flex items-center gap-4">
|
||||
<a class="hover:text-white" href="/">Dashboard</a>
|
||||
<a class="hover:text-white" href="/storage">Storage</a>
|
||||
<a class="hover:text-white" href="/shares">Shares</a>
|
||||
<a class="hover:text-white" href="/iscsi">iSCSI</a>
|
||||
<a class="hover:text-white" href="/protection">Data Protection</a>
|
||||
<a class="hover:text-white" href="/management">Management</a>
|
||||
<a class="hover:text-white opacity-50 cursor-not-allowed" href="#">Monitoring</a>
|
||||
<span id="auth-status" class="ml-4"></span>
|
||||
</nav>
|
||||
<!-- Navigation Menu -->
|
||||
<nav class="flex-1 overflow-y-auto py-4">
|
||||
<div class="px-2 space-y-1">
|
||||
<a href="/" class="nav-link flex items-center gap-3 px-4 py-3 rounded-lg text-slate-300 hover:bg-slate-800 hover:text-white transition-colors">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"></path>
|
||||
</svg>
|
||||
<span>Dashboard</span>
|
||||
</a>
|
||||
<a href="/storage" class="nav-link flex items-center gap-3 px-4 py-3 rounded-lg text-slate-300 hover:bg-slate-800 hover:text-white transition-colors">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4m0 5c0 2.21-3.582 4-8 4s-8-1.79-8-4"></path>
|
||||
</svg>
|
||||
<span>Storage</span>
|
||||
</a>
|
||||
<a href="/shares" class="nav-link flex items-center gap-3 px-4 py-3 rounded-lg text-slate-300 hover:bg-slate-800 hover:text-white transition-colors">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7h12m0 0l-4-4m4 4l-4 4m0 6H4m0 0l4 4m-4-4l4-4"></path>
|
||||
</svg>
|
||||
<span>Shares</span>
|
||||
</a>
|
||||
<a href="/iscsi" class="nav-link flex items-center gap-3 px-4 py-3 rounded-lg text-slate-300 hover:bg-slate-800 hover:text-white transition-colors">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 3v2m6-2v2M9 19v2m6-2v2M5 9H3m2 6H3m18-6h-2m2 6h-2M7 19h10a2 2 0 002-2V7a2 2 0 00-2-2H7a2 2 0 00-2 2v10a2 2 0 002 2zM9 9h6v6H9V9z"></path>
|
||||
</svg>
|
||||
<span>iSCSI</span>
|
||||
</a>
|
||||
<a href="/protection" class="nav-link flex items-center gap-3 px-4 py-3 rounded-lg text-slate-300 hover:bg-slate-800 hover:text-white transition-colors">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"></path>
|
||||
</svg>
|
||||
<span>Data Protection</span>
|
||||
</a>
|
||||
<a href="/management" class="nav-link flex items-center gap-3 px-4 py-3 rounded-lg text-slate-300 hover:bg-slate-800 hover:text-white transition-colors">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"></path>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
|
||||
</svg>
|
||||
<span>Management</span>
|
||||
</a>
|
||||
<a href="#" class="nav-link flex items-center gap-3 px-4 py-3 rounded-lg text-slate-500 opacity-50 cursor-not-allowed">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"></path>
|
||||
</svg>
|
||||
<span>Monitoring</span>
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Auth Status at Bottom -->
|
||||
<div class="p-4 border-t border-slate-800" id="auth-status-sidebar">
|
||||
<div class="text-sm text-slate-400">Loading...</div>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<!-- Top Header with Burger Menu -->
|
||||
<header class="sticky top-0 z-30 border-b border-slate-800 bg-slate-950/80 backdrop-blur lg:ml-64">
|
||||
<div class="px-4 py-3 flex items-center justify-between">
|
||||
<!-- Burger Menu Button (Mobile Only) -->
|
||||
<button id="burger-btn" onclick="toggleSidebar()" class="lg:hidden p-2 rounded-lg text-slate-300 hover:bg-slate-800 hover:text-white transition-colors">
|
||||
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path id="burger-icon" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path>
|
||||
<path id="close-icon" class="hidden" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<!-- Page Title (Mobile) / Spacer (Desktop) -->
|
||||
<div class="lg:hidden flex-1 text-center">
|
||||
<div class="font-semibold text-white">AtlasOS</div>
|
||||
</div>
|
||||
<div class="hidden lg:block flex-1"></div>
|
||||
|
||||
<!-- Auth Status (Desktop) -->
|
||||
<div class="hidden lg:block" id="auth-status-header">
|
||||
<div class="text-sm text-slate-400">Loading...</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="mx-auto max-w-6xl px-4 py-8">
|
||||
<!-- Main Content -->
|
||||
<main class="lg:ml-64 min-h-screen">
|
||||
<div class="px-4 py-6 lg:px-6 lg:py-8">
|
||||
{{$ct := getContentTemplate .}}
|
||||
{{if eq $ct "storage-content"}}
|
||||
{{template "storage-content" .}}
|
||||
@@ -55,40 +127,90 @@
|
||||
{{end}}
|
||||
</main>
|
||||
|
||||
<footer class="mx-auto max-w-6xl px-4 pb-10 text-xs text-slate-500">
|
||||
<div class="border-t border-slate-800 pt-4 flex items-center justify-between">
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer class="lg:ml-64 border-t border-slate-800 bg-slate-950/80 px-4 py-6 text-xs text-slate-500">
|
||||
<div class="flex flex-col sm:flex-row items-center justify-between gap-2">
|
||||
<span>AtlasOS • {{nowRFC3339}}</span>
|
||||
<span>Build: {{index .Build "version"}}</span>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
// Toggle sidebar for mobile
|
||||
function toggleSidebar() {
|
||||
const sidebar = document.getElementById('sidebar');
|
||||
const overlay = document.getElementById('mobile-overlay');
|
||||
const burgerIcon = document.getElementById('burger-icon');
|
||||
const closeIcon = document.getElementById('close-icon');
|
||||
|
||||
if (sidebar.classList.contains('-translate-x-full')) {
|
||||
sidebar.classList.remove('-translate-x-full');
|
||||
overlay.classList.remove('hidden');
|
||||
burgerIcon.classList.add('hidden');
|
||||
closeIcon.classList.remove('hidden');
|
||||
document.body.style.overflow = 'hidden';
|
||||
} else {
|
||||
sidebar.classList.add('-translate-x-full');
|
||||
overlay.classList.add('hidden');
|
||||
burgerIcon.classList.remove('hidden');
|
||||
closeIcon.classList.add('hidden');
|
||||
document.body.style.overflow = '';
|
||||
}
|
||||
}
|
||||
|
||||
// Close sidebar when clicking nav link on mobile
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const navLinks = document.querySelectorAll('.nav-link');
|
||||
navLinks.forEach(link => {
|
||||
link.addEventListener('click', function() {
|
||||
if (window.innerWidth < 1024) {
|
||||
toggleSidebar();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Update active nav link based on current URL
|
||||
const currentPath = window.location.pathname;
|
||||
navLinks.forEach(link => {
|
||||
if (link.getAttribute('href') === currentPath) {
|
||||
link.classList.add('bg-slate-800', 'text-white');
|
||||
link.classList.remove('text-slate-300');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Update auth status in navigation
|
||||
function updateAuthStatus() {
|
||||
const authStatusEl = document.getElementById('auth-status');
|
||||
if (!authStatusEl) return;
|
||||
const authStatusHeader = document.getElementById('auth-status-header');
|
||||
const authStatusSidebar = document.getElementById('auth-status-sidebar');
|
||||
|
||||
const token = localStorage.getItem('atlas_token');
|
||||
const userStr = localStorage.getItem('atlas_user');
|
||||
|
||||
if (token && userStr) {
|
||||
const authHTML = (token && userStr) ? (() => {
|
||||
try {
|
||||
const user = JSON.parse(userStr);
|
||||
authStatusEl.innerHTML = `
|
||||
<span class="text-slate-400">${user.username || 'User'}</span>
|
||||
<button onclick="handleLogout()" class="ml-2 px-2 py-1 text-xs bg-slate-700 hover:bg-slate-600 text-white rounded">
|
||||
Logout
|
||||
</button>
|
||||
return `
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-slate-300 text-sm">${user.username || 'User'}</span>
|
||||
<button onclick="handleLogout()" class="px-2 py-1 text-xs bg-slate-700 hover:bg-slate-600 text-white rounded transition-colors">
|
||||
Logout
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
} catch {
|
||||
authStatusEl.innerHTML = `
|
||||
<a href="/login" class="px-2 py-1 text-xs bg-blue-600 hover:bg-blue-700 text-white rounded">Login</a>
|
||||
return `
|
||||
<a href="/login" class="px-2 py-1 text-xs bg-blue-600 hover:bg-blue-700 text-white rounded transition-colors">Login</a>
|
||||
`;
|
||||
}
|
||||
} else {
|
||||
authStatusEl.innerHTML = `
|
||||
<a href="/login" class="px-2 py-1 text-xs bg-blue-600 hover:bg-blue-700 text-white rounded">Login</a>
|
||||
`;
|
||||
}
|
||||
})() : `
|
||||
<a href="/login" class="px-2 py-1 text-xs bg-blue-600 hover:bg-blue-700 text-white rounded transition-colors">Login</a>
|
||||
`;
|
||||
|
||||
if (authStatusHeader) authStatusHeader.innerHTML = authHTML;
|
||||
if (authStatusSidebar) authStatusSidebar.innerHTML = authHTML;
|
||||
}
|
||||
|
||||
function handleLogout() {
|
||||
@@ -103,6 +225,22 @@
|
||||
} else {
|
||||
updateAuthStatus();
|
||||
}
|
||||
|
||||
// Close sidebar on window resize to desktop
|
||||
window.addEventListener('resize', function() {
|
||||
if (window.innerWidth >= 1024) {
|
||||
const sidebar = document.getElementById('sidebar');
|
||||
const overlay = document.getElementById('mobile-overlay');
|
||||
const burgerIcon = document.getElementById('burger-icon');
|
||||
const closeIcon = document.getElementById('close-icon');
|
||||
|
||||
sidebar.classList.add('-translate-x-full');
|
||||
overlay.classList.add('hidden');
|
||||
burgerIcon.classList.remove('hidden');
|
||||
closeIcon.classList.add('hidden');
|
||||
document.body.style.overflow = '';
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,33 +1,33 @@
|
||||
{{define "storage-content"}}
|
||||
<div class="space-y-6">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="space-y-4 sm:space-y-6">
|
||||
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
|
||||
<div>
|
||||
<h1 class="text-3xl font-bold text-white mb-2">Storage Management</h1>
|
||||
<p class="text-slate-400">Manage storage pools, datasets, and volumes</p>
|
||||
<h1 class="text-2xl sm:text-3xl font-bold text-white mb-2">Storage Management</h1>
|
||||
<p class="text-sm sm:text-base text-slate-400">Manage storage pools, datasets, and volumes</p>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<button onclick="showCreatePoolModal()" class="px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg text-sm font-medium">
|
||||
<div class="flex flex-col sm:flex-row gap-2">
|
||||
<button onclick="showCreatePoolModal()" class="px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg text-sm font-medium transition-colors">
|
||||
Create Pool
|
||||
</button>
|
||||
<button onclick="showImportPoolModal()" class="px-4 py-2 bg-slate-700 hover:bg-slate-600 text-white rounded-lg text-sm font-medium">
|
||||
<button onclick="showImportPoolModal()" class="px-4 py-2 bg-slate-700 hover:bg-slate-600 text-white rounded-lg text-sm font-medium transition-colors">
|
||||
Import Pool
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tabs -->
|
||||
<div class="border-b border-slate-800">
|
||||
<nav class="flex gap-4">
|
||||
<button onclick="switchTab('pools')" id="tab-pools" class="tab-button px-4 py-2 border-b-2 border-blue-600 text-blue-400 font-medium">
|
||||
<div class="border-b border-slate-800 overflow-x-auto">
|
||||
<nav class="flex gap-2 sm:gap-4 min-w-max">
|
||||
<button onclick="switchTab('pools')" id="tab-pools" class="tab-button px-3 sm:px-4 py-2 border-b-2 border-blue-600 text-blue-400 font-medium whitespace-nowrap text-sm sm:text-base">
|
||||
Pools
|
||||
</button>
|
||||
<button onclick="switchTab('datasets')" id="tab-datasets" class="tab-button px-4 py-2 border-b-2 border-transparent text-slate-400 hover:text-slate-300">
|
||||
<button onclick="switchTab('datasets')" id="tab-datasets" class="tab-button px-3 sm:px-4 py-2 border-b-2 border-transparent text-slate-400 hover:text-slate-300 whitespace-nowrap text-sm sm:text-base">
|
||||
Datasets
|
||||
</button>
|
||||
<button onclick="switchTab('zvols')" id="tab-zvols" class="tab-button px-4 py-2 border-b-2 border-transparent text-slate-400 hover:text-slate-300">
|
||||
<button onclick="switchTab('zvols')" id="tab-zvols" class="tab-button px-3 sm:px-4 py-2 border-b-2 border-transparent text-slate-400 hover:text-slate-300 whitespace-nowrap text-sm sm:text-base">
|
||||
Volumes
|
||||
</button>
|
||||
<button onclick="switchTab('disks')" id="tab-disks" class="tab-button px-4 py-2 border-b-2 border-transparent text-slate-400 hover:text-slate-300">
|
||||
<button onclick="switchTab('disks')" id="tab-disks" class="tab-button px-3 sm:px-4 py-2 border-b-2 border-transparent text-slate-400 hover:text-slate-300 whitespace-nowrap text-sm sm:text-base">
|
||||
Disks
|
||||
</button>
|
||||
</nav>
|
||||
@@ -100,7 +100,7 @@
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<!-- Visual Disk Grid -->
|
||||
<div id="disks-visual" class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6 gap-4 mb-6">
|
||||
<div id="disks-visual" class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 gap-3 sm:gap-4 mb-6">
|
||||
<p class="text-slate-400 text-sm col-span-full">Loading...</p>
|
||||
</div>
|
||||
|
||||
@@ -147,8 +147,8 @@
|
||||
</div>
|
||||
|
||||
<!-- Create Pool Modal -->
|
||||
<div id="create-pool-modal" class="hidden fixed inset-0 bg-black/50 flex items-center justify-center z-50">
|
||||
<div class="bg-slate-800 rounded-lg border border-slate-700 p-6 max-w-md w-full mx-4">
|
||||
<div id="create-pool-modal" class="hidden fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4">
|
||||
<div class="bg-slate-800 rounded-lg border border-slate-700 p-4 sm:p-6 max-w-md w-full max-h-[90vh] overflow-y-auto">
|
||||
<h3 class="text-xl font-semibold text-white mb-4">Create Storage Pool</h3>
|
||||
<form id="create-pool-form" onsubmit="createPool(event)" class="space-y-4">
|
||||
<div>
|
||||
@@ -173,8 +173,8 @@
|
||||
</div>
|
||||
|
||||
<!-- Import Pool Modal -->
|
||||
<div id="import-pool-modal" class="hidden fixed inset-0 bg-black/50 flex items-center justify-center z-50">
|
||||
<div class="bg-slate-800 rounded-lg border border-slate-700 p-6 max-w-md w-full mx-4">
|
||||
<div id="import-pool-modal" class="hidden fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4">
|
||||
<div class="bg-slate-800 rounded-lg border border-slate-700 p-4 sm:p-6 max-w-md w-full max-h-[90vh] overflow-y-auto">
|
||||
<h3 class="text-xl font-semibold text-white mb-4">Import Storage Pool</h3>
|
||||
<form id="import-pool-form" onsubmit="importPool(event)" class="space-y-4">
|
||||
<div>
|
||||
@@ -200,8 +200,8 @@
|
||||
</div>
|
||||
|
||||
<!-- Create Dataset Modal -->
|
||||
<div id="create-dataset-modal" class="hidden fixed inset-0 bg-black/50 flex items-center justify-center z-50">
|
||||
<div class="bg-slate-800 rounded-lg border border-slate-700 p-6 max-w-md w-full mx-4">
|
||||
<div id="create-dataset-modal" class="hidden fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4">
|
||||
<div class="bg-slate-800 rounded-lg border border-slate-700 p-4 sm:p-6 max-w-md w-full max-h-[90vh] overflow-y-auto">
|
||||
<h3 class="text-xl font-semibold text-white mb-4">Create Dataset</h3>
|
||||
<form id="create-dataset-form" onsubmit="createDataset(event)" class="space-y-4">
|
||||
<div>
|
||||
@@ -234,8 +234,8 @@
|
||||
</div>
|
||||
|
||||
<!-- Create Storage Volume Modal -->
|
||||
<div id="create-zvol-modal" class="hidden fixed inset-0 bg-black/50 flex items-center justify-center z-50">
|
||||
<div class="bg-slate-800 rounded-lg border border-slate-700 p-6 max-w-md w-full mx-4">
|
||||
<div id="create-zvol-modal" class="hidden fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4">
|
||||
<div class="bg-slate-800 rounded-lg border border-slate-700 p-4 sm:p-6 max-w-md w-full max-h-[90vh] overflow-y-auto">
|
||||
<h3 class="text-xl font-semibold text-white mb-4">Create Storage Volume</h3>
|
||||
<form id="create-zvol-form" onsubmit="createZVOL(event)" class="space-y-4">
|
||||
<div>
|
||||
|
||||
Reference in New Issue
Block a user