fix storage pool, datasets,volume and disk
Some checks failed
CI / test-build (push) Has been cancelled
Some checks failed
CI / test-build (push) Has been cancelled
This commit is contained in:
@@ -319,7 +319,16 @@ async function loadPools() {
|
||||
|
||||
// Handle HTTP errors
|
||||
if (!res.ok) {
|
||||
const errorMsg = (data && data.error) ? data.error : `HTTP ${res.status}: Failed to load pools`;
|
||||
let errorMsg = `HTTP ${res.status}: Failed to load pools`;
|
||||
if (data) {
|
||||
if (data.message) {
|
||||
errorMsg = data.message;
|
||||
if (data.details) errorMsg += ': ' + data.details;
|
||||
} else if (data.error) {
|
||||
errorMsg = data.error;
|
||||
if (data.details) errorMsg += ': ' + data.details;
|
||||
}
|
||||
}
|
||||
listEl.innerHTML = `<p class="text-red-400 text-sm">Error: ${errorMsg}</p>`;
|
||||
return;
|
||||
}
|
||||
@@ -334,7 +343,14 @@ async function loadPools() {
|
||||
if (!Array.isArray(data)) {
|
||||
// Log the actual response for debugging
|
||||
console.error('Invalid response format:', data);
|
||||
const errorMsg = (data.error) ? data.error : 'Invalid response format: expected array';
|
||||
let errorMsg = 'Invalid response format: expected array';
|
||||
if (data.message) {
|
||||
errorMsg = data.message;
|
||||
if (data.details) errorMsg += ': ' + data.details;
|
||||
} else if (data.error) {
|
||||
errorMsg = data.error;
|
||||
if (data.details) errorMsg += ': ' + data.details;
|
||||
}
|
||||
listEl.innerHTML = `<p class="text-red-400 text-sm">Error: ${errorMsg}</p>`;
|
||||
return;
|
||||
}
|
||||
@@ -502,26 +518,32 @@ async function loadDisks() {
|
||||
|
||||
// Visual disk blocks (like QNAP) - using slate theme with numbered slots
|
||||
visualEl.innerHTML = disks.map((disk, index) => {
|
||||
// Available disks - using slate theme colors
|
||||
const slotNumber = index + 1;
|
||||
const statusColor = 'bg-slate-700';
|
||||
const statusBorder = 'border-slate-500';
|
||||
const isAvailable = disk.status === 'available';
|
||||
|
||||
// Set colors based on availability
|
||||
const statusColor = isAvailable ? 'bg-slate-700' : 'bg-slate-800';
|
||||
const statusBorder = isAvailable ? 'border-slate-500' : 'border-slate-600';
|
||||
const statusIndicator = isAvailable ? 'bg-green-500' : 'bg-red-500';
|
||||
const statusText = isAvailable ? 'Available' : 'Unavailable';
|
||||
const cursorClass = isAvailable ? 'cursor-pointer' : 'cursor-not-allowed opacity-75';
|
||||
const hoverClass = isAvailable ? 'hover:scale-105 hover:shadow-xl hover:shadow-blue-500/20 hover:-translate-y-1 hover:border-blue-500' : '';
|
||||
|
||||
return `
|
||||
<div class="group relative">
|
||||
<div class="disk-block ${statusColor} ${statusBorder} border-2 rounded-xl p-4 min-w-[140px] cursor-pointer transition-all duration-200 hover:scale-105 hover:shadow-xl hover:shadow-blue-500/20 hover:-translate-y-1 hover:border-blue-500"
|
||||
title="Slot ${slotNumber}\n${disk.name}\n${disk.size || 'Unknown size'}\n${disk.path || `/dev/${disk.name}`}"
|
||||
onclick="selectDisk('${disk.name}')">
|
||||
<div class="disk-block ${statusColor} ${statusBorder} border-2 rounded-xl p-4 min-w-[140px] ${cursorClass} transition-all duration-200 ${hoverClass}"
|
||||
title="Slot ${slotNumber}\n${disk.name}\n${disk.size || 'Unknown size'}\n${disk.path || `/dev/${disk.name}`}\nStatus: ${statusText}"
|
||||
${isAvailable ? `onclick="selectDisk('${disk.name}')"` : ''}>
|
||||
<!-- Slot Number Badge -->
|
||||
<div class="absolute -top-2 -left-2 w-8 h-8 rounded-full bg-blue-600 border-2 border-slate-800 flex items-center justify-center text-white font-bold text-xs shadow-lg z-10">
|
||||
<div class="absolute -top-2 -left-2 w-8 h-8 rounded-full ${isAvailable ? 'bg-blue-600' : 'bg-slate-600'} border-2 border-slate-800 flex items-center justify-center text-white font-bold text-xs shadow-lg z-10">
|
||||
${slotNumber}
|
||||
</div>
|
||||
|
||||
<!-- Disk Icon Container -->
|
||||
<div class="flex flex-col items-center justify-center pt-2">
|
||||
<div class="w-20 h-20 rounded-xl bg-gradient-to-br from-slate-600 to-slate-700 flex items-center justify-center mb-3 border-2 border-slate-500/50 group-hover:border-blue-500/70 group-hover:from-blue-600/30 group-hover:to-slate-700 transition-all shadow-inner">
|
||||
<div class="w-20 h-20 rounded-xl bg-gradient-to-br ${isAvailable ? 'from-slate-600 to-slate-700' : 'from-slate-700 to-slate-800'} flex items-center justify-center mb-3 border-2 border-slate-500/50 ${isAvailable ? 'group-hover:border-blue-500/70 group-hover:from-blue-600/30 group-hover:to-slate-700' : ''} transition-all shadow-inner">
|
||||
<!-- Disk Icon -->
|
||||
<svg class="w-12 h-12 text-slate-200 group-hover:text-blue-400 transition-colors" fill="currentColor" viewBox="0 0 20 20">
|
||||
<svg class="w-12 h-12 ${isAvailable ? 'text-slate-200 group-hover:text-blue-400' : 'text-slate-400'} transition-colors" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path d="M4 3a2 2 0 100 4h12a2 2 0 100-4H4z"></path>
|
||||
<path fill-rule="evenodd" d="M3 8h14v7a2 2 0 01-2 2H5a2 2 0 01-2-2V8zm5 3a1 1 0 011-1h2a1 1 0 110 2H9a1 1 0 01-1-1z" clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
@@ -529,21 +551,24 @@ async function loadDisks() {
|
||||
|
||||
<!-- Device Name -->
|
||||
<div class="text-center w-full">
|
||||
<div class="text-slate-100 font-bold text-base mb-1 group-hover:text-blue-400 transition-colors font-mono">
|
||||
<div class="${isAvailable ? 'text-slate-100 group-hover:text-blue-400' : 'text-slate-400'} font-bold text-base mb-1 transition-colors font-mono">
|
||||
${disk.name}
|
||||
</div>
|
||||
<div class="text-slate-300 text-xs font-semibold mb-1">
|
||||
<div class="${isAvailable ? 'text-slate-300' : 'text-slate-500'} text-xs font-semibold mb-1">
|
||||
${disk.size || 'N/A'}
|
||||
</div>
|
||||
<div class="text-slate-400 text-xs font-mono">
|
||||
<div class="${isAvailable ? 'text-slate-400' : 'text-slate-600'} text-xs font-mono">
|
||||
${disk.path || `/dev/${disk.name}`}
|
||||
</div>
|
||||
<div class="text-xs font-semibold mt-1 ${isAvailable ? 'text-green-400' : 'text-red-400'}">
|
||||
${statusText}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Status indicator -->
|
||||
<div class="absolute top-2 right-2">
|
||||
<div class="w-3 h-3 bg-green-500 rounded-full shadow-md border-2 border-slate-800 animate-pulse"></div>
|
||||
<div class="w-3 h-3 ${statusIndicator} rounded-full shadow-md border-2 border-slate-800 ${isAvailable ? 'animate-pulse' : ''}"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -552,8 +577,9 @@ async function loadDisks() {
|
||||
|
||||
// Detailed disk list with slot numbers
|
||||
listEl.innerHTML = disks.map((disk, index) => {
|
||||
const status = 'Available';
|
||||
const statusColor = 'bg-slate-700 text-slate-200';
|
||||
const isAvailable = disk.status === 'available';
|
||||
const status = isAvailable ? 'Available' : 'Unavailable';
|
||||
const statusColor = isAvailable ? 'bg-green-600 text-white' : 'bg-red-600 text-white';
|
||||
const diskPath = disk.path || `/dev/${disk.name}`;
|
||||
const slotNumber = index + 1;
|
||||
|
||||
@@ -577,9 +603,9 @@ async function loadDisks() {
|
||||
<!-- Disk Info -->
|
||||
<div class="flex-1">
|
||||
<div class="flex items-center gap-3 mb-2">
|
||||
<h3 class="text-lg font-semibold text-white font-mono">${disk.name}</h3>
|
||||
<h3 class="text-lg font-semibold ${isAvailable ? 'text-white' : 'text-slate-400'} font-mono">${disk.name}</h3>
|
||||
<span class="px-2 py-1 rounded text-xs font-medium ${statusColor}">${status}</span>
|
||||
<span class="text-xs text-slate-500 font-mono">${diskPath}</span>
|
||||
<span class="text-xs ${isAvailable ? 'text-slate-500' : 'text-slate-600'} font-mono">${diskPath}</span>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 md:grid-cols-3 gap-4 text-sm">
|
||||
${disk.size ? `
|
||||
@@ -716,8 +742,24 @@ async function createPool(e) {
|
||||
alert('Pool created successfully');
|
||||
} else {
|
||||
// Check if pool appears in the list (might have been created despite error)
|
||||
const err = data?.error || 'Failed to create pool';
|
||||
alert(`Error: ${err}\n\nNote: The pool list has been refreshed. Please check if the pool was created.`);
|
||||
// Handle both error formats: APIError {code, message, details} or simple {error, details}
|
||||
let errMsg = 'Failed to create pool';
|
||||
if (data) {
|
||||
if (data.message) {
|
||||
// APIError format
|
||||
errMsg = data.message;
|
||||
if (data.details) {
|
||||
errMsg += ': ' + data.details;
|
||||
}
|
||||
} else if (data.error) {
|
||||
// Simple error format
|
||||
errMsg = data.error;
|
||||
if (data.details) {
|
||||
errMsg += ': ' + data.details;
|
||||
}
|
||||
}
|
||||
}
|
||||
alert(`Error: ${errMsg}\n\nNote: The pool list has been refreshed. Please check if the pool was created.`);
|
||||
}
|
||||
} catch (err) {
|
||||
// On network error, still try to refresh to see if pool was created
|
||||
@@ -851,8 +893,18 @@ async function deleteDataset(name) {
|
||||
loadDatasets();
|
||||
alert('Dataset deleted successfully');
|
||||
} else {
|
||||
const err = await res.json();
|
||||
alert(`Error: ${err.error || 'Failed to delete dataset'}`);
|
||||
const err = await res.json().catch(() => null);
|
||||
let errMsg = 'Failed to delete dataset';
|
||||
if (err) {
|
||||
if (err.message) {
|
||||
errMsg = err.message;
|
||||
if (err.details) errMsg += ': ' + err.details;
|
||||
} else if (err.error) {
|
||||
errMsg = err.error;
|
||||
if (err.details) errMsg += ': ' + err.details;
|
||||
}
|
||||
}
|
||||
alert(`Error: ${errMsg}`);
|
||||
}
|
||||
} catch (err) {
|
||||
alert(`Error: ${err.message}`);
|
||||
@@ -872,8 +924,18 @@ async function deleteZVOL(name) {
|
||||
loadZVOLs();
|
||||
alert('Storage volume deleted successfully');
|
||||
} else {
|
||||
const err = await res.json();
|
||||
alert(`Error: ${err.error || 'Failed to delete storage volume'}`);
|
||||
const err = await res.json().catch(() => null);
|
||||
let errMsg = 'Failed to delete storage volume';
|
||||
if (err) {
|
||||
if (err.message) {
|
||||
errMsg = err.message;
|
||||
if (err.details) errMsg += ': ' + err.details;
|
||||
} else if (err.error) {
|
||||
errMsg = err.error;
|
||||
if (err.details) errMsg += ': ' + err.details;
|
||||
}
|
||||
}
|
||||
alert(`Error: ${errMsg}`);
|
||||
}
|
||||
} catch (err) {
|
||||
alert(`Error: ${err.message}`);
|
||||
|
||||
Reference in New Issue
Block a user