diff --git a/weed/admin/dash/admin_server.go b/weed/admin/dash/admin_server.go
index 6fb158894..d15951e49 100644
--- a/weed/admin/dash/admin_server.go
+++ b/weed/admin/dash/admin_server.go
@@ -151,16 +151,22 @@ type ClusterVolumesData struct {
DataCenterCount int `json:"datacenter_count"`
RackCount int `json:"rack_count"`
DiskTypeCount int `json:"disk_type_count"`
+ CollectionCount int `json:"collection_count"`
// Conditional display flags
ShowDataCenterColumn bool `json:"show_datacenter_column"`
ShowRackColumn bool `json:"show_rack_column"`
ShowDiskTypeColumn bool `json:"show_disk_type_column"`
+ ShowCollectionColumn bool `json:"show_collection_column"`
// Single values when only one exists
SingleDataCenter string `json:"single_datacenter"`
SingleRack string `json:"single_rack"`
SingleDiskType string `json:"single_disk_type"`
+ SingleCollection string `json:"single_collection"`
+
+ // Filtering
+ FilterCollection string `json:"filter_collection"`
}
type CollectionInfo struct {
@@ -795,8 +801,8 @@ func (s *AdminServer) GetClusterVolumeServers() (*ClusterVolumeServersData, erro
}, nil
}
-// GetClusterVolumes retrieves cluster volumes data with pagination and sorting
-func (s *AdminServer) GetClusterVolumes(page int, pageSize int, sortBy string, sortOrder string) (*ClusterVolumesData, error) {
+// GetClusterVolumes retrieves cluster volumes data with pagination, sorting, and optional collection filtering
+func (s *AdminServer) GetClusterVolumes(page int, pageSize int, sortBy string, sortOrder string, collection string) (*ClusterVolumesData, error) {
// Set defaults
if page < 1 {
page = 1
@@ -812,7 +818,6 @@ func (s *AdminServer) GetClusterVolumes(page int, pageSize int, sortBy string, s
}
var volumes []VolumeInfo
var totalSize int64
- volumeID := 1
// Get detailed volume information via gRPC
err := s.WithMasterClient(func(client master_pb.SeaweedClient) error {
@@ -840,7 +845,7 @@ func (s *AdminServer) GetClusterVolumes(page int, pageSize int, sortBy string, s
}
volume := VolumeInfo{
- ID: volumeID,
+ ID: int(volInfo.Id), // Use actual SeaweedFS volume ID
Server: node.Id,
DataCenter: dc.Id,
Rack: rack.Id,
@@ -853,7 +858,6 @@ func (s *AdminServer) GetClusterVolumes(page int, pageSize int, sortBy string, s
}
volumes = append(volumes, volume)
totalSize += volume.Size
- volumeID++
}
}
}
@@ -868,10 +872,25 @@ func (s *AdminServer) GetClusterVolumes(page int, pageSize int, sortBy string, s
return nil, err
}
- // Calculate unique data center, rack, and disk type counts from all volumes
+ // Filter by collection if specified
+ if collection != "" {
+ var filteredVolumes []VolumeInfo
+ var filteredTotalSize int64
+ for _, volume := range volumes {
+ if volume.Collection == collection {
+ filteredVolumes = append(filteredVolumes, volume)
+ filteredTotalSize += volume.Size
+ }
+ }
+ volumes = filteredVolumes
+ totalSize = filteredTotalSize
+ }
+
+ // Calculate unique data center, rack, disk type, and collection counts from all volumes
dataCenterMap := make(map[string]bool)
rackMap := make(map[string]bool)
diskTypeMap := make(map[string]bool)
+ collectionMap := make(map[string]bool)
for _, volume := range volumes {
if volume.DataCenter != "" {
dataCenterMap[volume.DataCenter] = true
@@ -884,10 +903,14 @@ func (s *AdminServer) GetClusterVolumes(page int, pageSize int, sortBy string, s
diskType = "hdd" // Default to hdd if not specified
}
diskTypeMap[diskType] = true
+ if volume.Collection != "" {
+ collectionMap[volume.Collection] = true
+ }
}
dataCenterCount := len(dataCenterMap)
rackCount := len(rackMap)
diskTypeCount := len(diskTypeMap)
+ collectionCount := len(collectionMap)
// Sort volumes
s.sortVolumes(volumes, sortBy, sortOrder)
@@ -915,8 +938,9 @@ func (s *AdminServer) GetClusterVolumes(page int, pageSize int, sortBy string, s
showDataCenterColumn := dataCenterCount > 1
showRackColumn := rackCount > 1
showDiskTypeColumn := diskTypeCount > 1
+ showCollectionColumn := collectionCount > 1 && collection == "" // Hide column when filtering by collection
- var singleDataCenter, singleRack, singleDiskType string
+ var singleDataCenter, singleRack, singleDiskType, singleCollection string
if dataCenterCount == 1 {
for dc := range dataCenterMap {
singleDataCenter = dc
@@ -935,6 +959,12 @@ func (s *AdminServer) GetClusterVolumes(page int, pageSize int, sortBy string, s
break
}
}
+ if collectionCount == 1 {
+ for collection := range collectionMap {
+ singleCollection = collection
+ break
+ }
+ }
return &ClusterVolumesData{
Volumes: volumes,
@@ -949,12 +979,16 @@ func (s *AdminServer) GetClusterVolumes(page int, pageSize int, sortBy string, s
DataCenterCount: dataCenterCount,
RackCount: rackCount,
DiskTypeCount: diskTypeCount,
+ CollectionCount: collectionCount,
ShowDataCenterColumn: showDataCenterColumn,
ShowRackColumn: showRackColumn,
ShowDiskTypeColumn: showDiskTypeColumn,
+ ShowCollectionColumn: showCollectionColumn,
SingleDataCenter: singleDataCenter,
SingleRack: singleRack,
SingleDiskType: singleDiskType,
+ SingleCollection: singleCollection,
+ FilterCollection: collection,
}, nil
}
diff --git a/weed/admin/handlers/cluster_handlers.go b/weed/admin/handlers/cluster_handlers.go
index 515cdaecb..3c4107533 100644
--- a/weed/admin/handlers/cluster_handlers.go
+++ b/weed/admin/handlers/cluster_handlers.go
@@ -68,9 +68,10 @@ func (h *ClusterHandlers) ShowClusterVolumes(c *gin.Context) {
sortBy := c.DefaultQuery("sortBy", "id")
sortOrder := c.DefaultQuery("sortOrder", "asc")
+ collection := c.Query("collection") // Optional collection filter
// Get cluster volumes data
- volumesData, err := h.adminServer.GetClusterVolumes(page, pageSize, sortBy, sortOrder)
+ volumesData, err := h.adminServer.GetClusterVolumes(page, pageSize, sortBy, sortOrder, collection)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get cluster volumes: " + err.Error()})
return
diff --git a/weed/admin/view/app/cluster_collections.templ b/weed/admin/view/app/cluster_collections.templ
index c91fab539..972998d18 100644
--- a/weed/admin/view/app/cluster_collections.templ
+++ b/weed/admin/view/app/cluster_collections.templ
@@ -131,13 +131,17 @@ templ ClusterCollections(data dash.ClusterCollectionsData) {
for _, collection := range data.Collections {
- {collection.Name}
+
+ {collection.Name}
+
|
-
-
- {fmt.Sprintf("%d", collection.VolumeCount)}
-
+
+
+
+ {fmt.Sprintf("%d", collection.VolumeCount)}
+
+
|
diff --git a/weed/admin/view/app/cluster_collections_templ.go b/weed/admin/view/app/cluster_collections_templ.go
index 1ab6ef924..bb7187ece 100644
--- a/weed/admin/view/app/cluster_collections_templ.go
+++ b/weed/admin/view/app/cluster_collections_templ.go
@@ -96,157 +96,175 @@ func ClusterCollections(data dash.ClusterCollectionsData) templ.Component {
return templ_7745c5c3_Err
}
for _, collection := range data.Collections {
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, " ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, " | ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "\" class=\"text-decoration-none\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var7 string
- templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", collection.VolumeCount))
+ templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(collection.Name)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_collections.templ`, Line: 139, Col: 90}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_collections.templ`, Line: 135, Col: 72}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, " | ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, " | | ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "\" class=\"text-decoration-none\"> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var9 string
- templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(formatBytes(collection.TotalSize))
+ templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", collection.VolumeCount))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_collections.templ`, Line: 151, Col: 82}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_collections.templ`, Line: 142, Col: 94}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, " | ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, " | ")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var10 string
+ templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", collection.FileCount))
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_collections.templ`, Line: 149, Col: 88}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, " | ")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var11 string
+ templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(formatBytes(collection.TotalSize))
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_collections.templ`, Line: 155, Col: 82}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, " | ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
for i, diskType := range collection.DiskTypes {
if i > 0 {
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, " ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, " ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- var templ_7745c5c3_Var10 = []any{fmt.Sprintf("badge bg-%s me-1", getDiskTypeColor(diskType))}
- templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var10...)
+ var templ_7745c5c3_Var12 = []any{fmt.Sprintf("badge bg-%s me-1", getDiskTypeColor(diskType))}
+ templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var12...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- var templ_7745c5c3_Var12 string
- templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(diskType)
+ var templ_7745c5c3_Var14 string
+ templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(diskType)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_collections.templ`, Line: 159, Col: 131}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_collections.templ`, Line: 163, Col: 131}
}
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12))
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, " ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, " ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
if len(collection.DiskTypes) == 0 {
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "Unknown")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "Unknown")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, " | | ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "\" onclick=\"confirmDeleteCollection(this)\"> | ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, " ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else {
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "No Collections FoundNo collections are currently configured in the cluster. ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "No Collections FoundNo collections are currently configured in the cluster. ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, " Last updated: ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, " Last updated: ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- var templ_7745c5c3_Var14 string
- templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(data.LastUpdated.Format("2006-01-02 15:04:05"))
+ var templ_7745c5c3_Var16 string
+ templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(data.LastUpdated.Format("2006-01-02 15:04:05"))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_collections.templ`, Line: 206, Col: 81}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_collections.templ`, Line: 210, Col: 81}
}
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, " Are you sure you want to delete the collection ? This action cannot be undone. All volumes in this collection will be affected. ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "Are you sure you want to delete the collection ? This action cannot be undone. All volumes in this collection will be affected. ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
diff --git a/weed/admin/view/app/cluster_volumes.templ b/weed/admin/view/app/cluster_volumes.templ
index 8d4952db2..7c771b46e 100644
--- a/weed/admin/view/app/cluster_volumes.templ
+++ b/weed/admin/view/app/cluster_volumes.templ
@@ -7,9 +7,21 @@ import (
templ ClusterVolumes(data dash.ClusterVolumesData) {
-
- Cluster Volumes
-
+
+
+ Cluster Volumes
+
+ if data.FilterCollection != "" {
+
+ }
+
|
}
-
- {volume.Collection}
- |
+ if data.ShowCollectionColumn {
+
+ {volume.Collection}
+ |
+ }
{formatBytes(volume.Size)} |
{fmt.Sprintf("%d", volume.FileCount)} |
@@ -485,15 +509,7 @@ func countUniqueDiskTypes(volumes []dash.VolumeInfo) int {
return len(diskTypeMap)
}
-func countUniqueCollections(volumes []dash.VolumeInfo) int {
- collectionMap := make(map[string]bool)
- for _, volume := range volumes {
- if volume.Collection != "" {
- collectionMap[volume.Collection] = true
- }
- }
- return len(collectionMap)
-}
+
templ getSortIcon(column, currentSort, currentOrder string) {
if column != currentSort {
diff --git a/weed/admin/view/app/cluster_volumes_templ.go b/weed/admin/view/app/cluster_volumes_templ.go
index 58d896459..0b42bee59 100644
--- a/weed/admin/view/app/cluster_volumes_templ.go
+++ b/weed/admin/view/app/cluster_volumes_templ.go
@@ -34,96 +34,106 @@ func ClusterVolumes(data dash.ClusterVolumesData) templ.Component {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -762,16 +824,6 @@ func countUniqueDiskTypes(volumes []dash.VolumeInfo) int {
return len(diskTypeMap)
}
-func countUniqueCollections(volumes []dash.VolumeInfo) int {
- collectionMap := make(map[string]bool)
- for _, volume := range volumes {
- if volume.Collection != "" {
- collectionMap[volume.Collection] = true
- }
- }
- return len(collectionMap)
-}
-
func getSortIcon(column, currentSort, currentOrder string) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@@ -788,23 +840,23 @@ func getSortIcon(column, currentSort, currentOrder string) templ.Component {
}()
}
ctx = templ.InitializeContext(ctx)
- templ_7745c5c3_Var32 := templ.GetChildren(ctx)
- if templ_7745c5c3_Var32 == nil {
- templ_7745c5c3_Var32 = templ.NopComponent
+ templ_7745c5c3_Var34 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var34 == nil {
+ templ_7745c5c3_Var34 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
if column != currentSort {
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 82, "")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 90, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else if currentOrder == "asc" {
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 83, "")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 91, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else {
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 84, "")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 92, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
|