aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorchrislu <chris.lu@gmail.com>2025-07-04 14:45:13 -0700
committerchrislu <chris.lu@gmail.com>2025-07-04 14:45:13 -0700
commit302e62d4805c60f3fdb6620b01e85859d68078ed (patch)
tree89bffe09396140ba2bd2df7cb7a3f44a93e83b72
parentdf307375051ba26419630a50a79d60e976509b5b (diff)
downloadseaweedfs-302e62d4805c60f3fdb6620b01e85859d68078ed.tar.xz
seaweedfs-302e62d4805c60f3fdb6620b01e85859d68078ed.zip
link to volume details
-rw-r--r--weed/admin/view/app/cluster_volumes.templ6
-rw-r--r--weed/admin/view/app/cluster_volumes_templ.go2
2 files changed, 4 insertions, 4 deletions
diff --git a/weed/admin/view/app/cluster_volumes.templ b/weed/admin/view/app/cluster_volumes.templ
index e25b0da32..b4e1b8fd3 100644
--- a/weed/admin/view/app/cluster_volumes.templ
+++ b/weed/admin/view/app/cluster_volumes.templ
@@ -593,9 +593,9 @@ templ ClusterVolumes(data dash.ClusterVolumesData) {
}
function viewVolumeDetails(volumeId) {
- // Get the server from the current row
- const button = event.target.closest('button');
- const row = button.closest('tr');
+ // Get the server from the current row - works for both buttons and volume ID links
+ const clickedElement = event.target;
+ const row = clickedElement.closest('tr');
const serverCell = row.querySelector('td:nth-child(2) a');
const server = serverCell ? serverCell.textContent.trim() : 'unknown';
diff --git a/weed/admin/view/app/cluster_volumes_templ.go b/weed/admin/view/app/cluster_volumes_templ.go
index 21c595468..d2a82c704 100644
--- a/weed/admin/view/app/cluster_volumes_templ.go
+++ b/weed/admin/view/app/cluster_volumes_templ.go
@@ -1025,7 +1025,7 @@ func ClusterVolumes(data dash.ClusterVolumesData) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 111, "</small></div></div></div><!-- JavaScript for pagination and sorting --><script>\n // Initialize pagination links when page loads\n document.addEventListener('DOMContentLoaded', function() {\n // Add click handlers to pagination links\n document.querySelectorAll('.pagination-link').forEach(link => {\n link.addEventListener('click', function(e) {\n e.preventDefault();\n const page = this.getAttribute('data-page');\n goToPage(page);\n });\n });\n \n // Add click handlers to view details buttons\n document.querySelectorAll('.view-details-btn').forEach(button => {\n button.addEventListener('click', function(e) {\n e.preventDefault();\n const volumeId = this.getAttribute('data-volume-id');\n viewVolumeDetails(volumeId);\n });\n });\n\n // Add click handlers to volume ID links\n document.querySelectorAll('.volume-id-link').forEach(link => {\n link.addEventListener('click', function(e) {\n e.preventDefault();\n const volumeId = this.getAttribute('data-volume-id');\n viewVolumeDetails(volumeId);\n });\n });\n\n // Add click handlers to vacuum buttons\n document.querySelectorAll('.vacuum-btn').forEach(button => {\n button.addEventListener('click', function(e) {\n e.preventDefault();\n const volumeId = this.getAttribute('data-volume-id');\n const server = this.getAttribute('data-server');\n performVacuum(volumeId, server, this);\n });\n });\n });\n \n function goToPage(page) {\n const url = new URL(window.location);\n url.searchParams.set('page', page);\n window.location.href = url.toString();\n }\n \n function changePageSize() {\n const pageSize = document.getElementById('pageSizeSelect').value;\n const url = new URL(window.location);\n url.searchParams.set('pageSize', pageSize);\n url.searchParams.set('page', '1'); // Reset to first page\n window.location.href = url.toString();\n }\n \n function sortTable(column) {\n const url = new URL(window.location);\n const currentSort = url.searchParams.get('sortBy');\n const currentOrder = url.searchParams.get('sortOrder') || 'asc';\n \n let newOrder = 'asc';\n if (currentSort === column && currentOrder === 'asc') {\n newOrder = 'desc';\n }\n \n url.searchParams.set('sortBy', column);\n url.searchParams.set('sortOrder', newOrder);\n url.searchParams.set('page', '1'); // Reset to first page\n window.location.href = url.toString();\n }\n \n function exportVolumes() {\n // TODO: Implement volume export functionality\n alert('Export functionality to be implemented');\n }\n \n function viewVolumeDetails(volumeId) {\n // Get the server from the current row\n const button = event.target.closest('button');\n const row = button.closest('tr');\n const serverCell = row.querySelector('td:nth-child(2) a');\n const server = serverCell ? serverCell.textContent.trim() : 'unknown';\n \n window.location.href = `/cluster/volumes/${volumeId}/${encodeURIComponent(server)}`;\n }\n\n function performVacuum(volumeId, server, button) {\n // Disable button and show loading state\n const originalHTML = button.innerHTML;\n button.disabled = true;\n button.innerHTML = '<i class=\"fas fa-spinner fa-spin\"></i>';\n\n // Send vacuum request\n fetch(`/api/volumes/${volumeId}/${encodeURIComponent(server)}/vacuum`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n }\n })\n .then(response => response.json())\n .then(data => {\n if (data.error) {\n showMessage(data.error, 'error');\n } else {\n showMessage(data.message || 'Volume vacuum started successfully', 'success');\n // Optionally refresh the page after a delay to show updated vacuum status\n setTimeout(() => {\n window.location.reload();\n }, 2000);\n }\n })\n .catch(error => {\n console.error('Error:', error);\n showMessage('Failed to start vacuum operation', 'error');\n })\n .finally(() => {\n // Re-enable button\n button.disabled = false;\n button.innerHTML = originalHTML;\n });\n }\n\n function showMessage(message, type) {\n // Create toast notification\n const toast = document.createElement('div');\n toast.className = `alert alert-${type === 'error' ? 'danger' : 'success'} alert-dismissible fade show position-fixed`;\n toast.style.top = '20px';\n toast.style.right = '20px';\n toast.style.zIndex = '9999';\n toast.style.minWidth = '300px';\n \n toast.innerHTML = `\n ${message}\n <button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"alert\"></button>\n `;\n \n document.body.appendChild(toast);\n \n // Auto-remove after 5 seconds\n setTimeout(() => {\n if (toast.parentNode) {\n toast.parentNode.removeChild(toast);\n }\n }, 5000);\n }\n </script>")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 111, "</small></div></div></div><!-- JavaScript for pagination and sorting --><script>\n // Initialize pagination links when page loads\n document.addEventListener('DOMContentLoaded', function() {\n // Add click handlers to pagination links\n document.querySelectorAll('.pagination-link').forEach(link => {\n link.addEventListener('click', function(e) {\n e.preventDefault();\n const page = this.getAttribute('data-page');\n goToPage(page);\n });\n });\n \n // Add click handlers to view details buttons\n document.querySelectorAll('.view-details-btn').forEach(button => {\n button.addEventListener('click', function(e) {\n e.preventDefault();\n const volumeId = this.getAttribute('data-volume-id');\n viewVolumeDetails(volumeId);\n });\n });\n\n // Add click handlers to volume ID links\n document.querySelectorAll('.volume-id-link').forEach(link => {\n link.addEventListener('click', function(e) {\n e.preventDefault();\n const volumeId = this.getAttribute('data-volume-id');\n viewVolumeDetails(volumeId);\n });\n });\n\n // Add click handlers to vacuum buttons\n document.querySelectorAll('.vacuum-btn').forEach(button => {\n button.addEventListener('click', function(e) {\n e.preventDefault();\n const volumeId = this.getAttribute('data-volume-id');\n const server = this.getAttribute('data-server');\n performVacuum(volumeId, server, this);\n });\n });\n });\n \n function goToPage(page) {\n const url = new URL(window.location);\n url.searchParams.set('page', page);\n window.location.href = url.toString();\n }\n \n function changePageSize() {\n const pageSize = document.getElementById('pageSizeSelect').value;\n const url = new URL(window.location);\n url.searchParams.set('pageSize', pageSize);\n url.searchParams.set('page', '1'); // Reset to first page\n window.location.href = url.toString();\n }\n \n function sortTable(column) {\n const url = new URL(window.location);\n const currentSort = url.searchParams.get('sortBy');\n const currentOrder = url.searchParams.get('sortOrder') || 'asc';\n \n let newOrder = 'asc';\n if (currentSort === column && currentOrder === 'asc') {\n newOrder = 'desc';\n }\n \n url.searchParams.set('sortBy', column);\n url.searchParams.set('sortOrder', newOrder);\n url.searchParams.set('page', '1'); // Reset to first page\n window.location.href = url.toString();\n }\n \n function exportVolumes() {\n // TODO: Implement volume export functionality\n alert('Export functionality to be implemented');\n }\n \n function viewVolumeDetails(volumeId) {\n // Get the server from the current row - works for both buttons and volume ID links\n const clickedElement = event.target;\n const row = clickedElement.closest('tr');\n const serverCell = row.querySelector('td:nth-child(2) a');\n const server = serverCell ? serverCell.textContent.trim() : 'unknown';\n \n window.location.href = `/cluster/volumes/${volumeId}/${encodeURIComponent(server)}`;\n }\n\n function performVacuum(volumeId, server, button) {\n // Disable button and show loading state\n const originalHTML = button.innerHTML;\n button.disabled = true;\n button.innerHTML = '<i class=\"fas fa-spinner fa-spin\"></i>';\n\n // Send vacuum request\n fetch(`/api/volumes/${volumeId}/${encodeURIComponent(server)}/vacuum`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n }\n })\n .then(response => response.json())\n .then(data => {\n if (data.error) {\n showMessage(data.error, 'error');\n } else {\n showMessage(data.message || 'Volume vacuum started successfully', 'success');\n // Optionally refresh the page after a delay to show updated vacuum status\n setTimeout(() => {\n window.location.reload();\n }, 2000);\n }\n })\n .catch(error => {\n console.error('Error:', error);\n showMessage('Failed to start vacuum operation', 'error');\n })\n .finally(() => {\n // Re-enable button\n button.disabled = false;\n button.innerHTML = originalHTML;\n });\n }\n\n function showMessage(message, type) {\n // Create toast notification\n const toast = document.createElement('div');\n toast.className = `alert alert-${type === 'error' ? 'danger' : 'success'} alert-dismissible fade show position-fixed`;\n toast.style.top = '20px';\n toast.style.right = '20px';\n toast.style.zIndex = '9999';\n toast.style.minWidth = '300px';\n \n toast.innerHTML = `\n ${message}\n <button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"alert\"></button>\n `;\n \n document.body.appendChild(toast);\n \n // Auto-remove after 5 seconds\n setTimeout(() => {\n if (toast.parentNode) {\n toast.parentNode.removeChild(toast);\n }\n }, 5000);\n }\n </script>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}