diff --git a/weed/admin/dash/admin_data.go b/weed/admin/dash/admin_data.go index 286613e95..bc61871bf 100644 --- a/weed/admin/dash/admin_data.go +++ b/weed/admin/dash/admin_data.go @@ -23,7 +23,7 @@ const ( type AdminData struct { Username string `json:"username"` TotalVolumes int `json:"total_volumes"` - TotalFiles int64 `json:"total_files"` + TotalChunks int64 `json:"total_chunks"` TotalSize int64 `json:"total_size"` VolumeSizeLimitMB uint64 `json:"volume_size_limit_mb"` MasterNodes []MasterNode `json:"master_nodes"` @@ -199,7 +199,7 @@ func (s *AdminServer) GetAdminData(username string) (AdminData, error) { adminData := AdminData{ Username: username, TotalVolumes: topology.TotalVolumes, - TotalFiles: topology.TotalFiles, + TotalChunks: topology.TotalChunks, TotalSize: topology.TotalSize, VolumeSizeLimitMB: volumeSizeLimitMB, MasterNodes: masterNodes, diff --git a/weed/admin/dash/admin_server.go b/weed/admin/dash/admin_server.go index 75587c99d..bfe965161 100644 --- a/weed/admin/dash/admin_server.go +++ b/weed/admin/dash/admin_server.go @@ -1928,9 +1928,20 @@ type ecVolumeCounts struct { deleteCount uint64 } +// volumeLiveCount is the live chunk count of one regular volume. Replicas +// mirror each other's needles and their deletes, so the fullest report is the +// volume's count — dividing each report by the copy count instead would lose +// a chunk to integer truncation and would halve a volume whose second replica +// has not reported yet. +type volumeLiveCount struct { + collection string + live uint64 +} + func collectCollectionStats(topologyInfo *master_pb.TopologyInfo) map[string]collectionStats { collectionMap := make(map[string]collectionStats) ecVolumeAgg := make(map[uint32]*ecVolumeCounts) + volumeAgg := make(map[uint32]*volumeLiveCount) for _, dc := range topologyInfo.DataCenterInfos { for _, rack := range dc.RackInfos { for _, node := range rack.DataNodeInfos { @@ -1951,10 +1962,18 @@ func collectCollectionStats(topologyInfo *master_pb.TopologyInfo) map[string]col if volInfo.Size >= volInfo.DeletedByteCount { data.LogicalSize += int64(volInfo.Size-volInfo.DeletedByteCount) / replicaCount } - if volInfo.FileCount >= volInfo.DeleteCount { - data.FileCount += int64(volInfo.FileCount-volInfo.DeleteCount) / replicaCount - } collectionMap[collection] = data + + if volInfo.FileCount >= volInfo.DeleteCount { + agg, ok := volumeAgg[volInfo.Id] + if !ok { + agg = &volumeLiveCount{collection: collection} + volumeAgg[volInfo.Id] = agg + } + if live := volInfo.FileCount - volInfo.DeleteCount; live > agg.live { + agg.live = live + } + } } for _, ecShardInfo := range diskInfo.EcShardInfos { collection := ecShardInfo.Collection @@ -1987,6 +2006,14 @@ func collectCollectionStats(topologyInfo *master_pb.TopologyInfo) map[string]col } } + // Fold the per-volume live counts in, one entry per volume id no matter + // how many replicas reported it. + for _, agg := range volumeAgg { + data := collectionMap[agg.collection] + data.FileCount += int64(agg.live) + collectionMap[agg.collection] = data + } + // Fold EC per-volume counts into the collection totals. fileCount is // deduped via max across every node reporting shards for the volume; // deleteCount is summed across the same nodes. @@ -2004,6 +2031,17 @@ func collectCollectionStats(topologyInfo *master_pb.TopologyInfo) map[string]col return collectionMap } +// totalCollectionFileCount is the cluster-wide live chunk count: the sum of +// every collection's deduped count. Volumes and EC volumes are reported by +// each replica or shard holder, so only this aggregation counts a chunk once. +func totalCollectionFileCount(topologyInfo *master_pb.TopologyInfo) int64 { + var total int64 + for _, stats := range collectCollectionStats(topologyInfo) { + total += stats.FileCount + } + return total +} + // getCollectionStats returns current collection statistics with caching func (s *AdminServer) getCollectionStats() (map[string]collectionStats, error) { now := time.Now() diff --git a/weed/admin/dash/cluster_topology.go b/weed/admin/dash/cluster_topology.go index 3bc0c02b5..b91f3dd6c 100644 --- a/weed/admin/dash/cluster_topology.go +++ b/weed/admin/dash/cluster_topology.go @@ -124,13 +124,6 @@ func (s *AdminServer) getTopologyViaGRPC(topology *ClusterTopology) error { } if resp.TopologyInfo != nil { - // Dedupe EC volume file counts across the nodes that report - // shards for the same volume: every shard holder reports the - // same .ecx-derived file_count, so we keep the max and sum - // node-local tombstones. - ecFile := make(map[uint32]uint64) - ecDel := make(map[uint32]uint64) - // Process gRPC response for _, dc := range resp.TopologyInfo.DataCenterInfos { dataCenter := DataCenter{ @@ -149,7 +142,6 @@ func (s *AdminServer) getTopologyViaGRPC(topology *ClusterTopology) error { var totalVolumes int64 var totalMaxVolumes int64 var totalSize int64 - var totalFiles int64 // Prefer the real physical disk capacity the volume server // reports per disk; the slot-based estimate overstates capacity // when maxVolumeCount is configured higher than the disk holds. @@ -167,23 +159,14 @@ func (s *AdminServer) getTopologyViaGRPC(topology *ClusterTopology) error { // Sum up individual volume information for _, volInfo := range diskInfo.VolumeInfos { totalSize += int64(volInfo.Size) - totalFiles += int64(volInfo.FileCount) } - // Sum up EC shard sizes on this node and collect - // volume-wide file/delete counts for later folding - // into topology.TotalFiles. ShardSizes is local to - // this node, so summing across nodes is correct; - // FileCount/DeleteCount are per-volume and must be - // deduped per volume id. + // ShardSizes is local to this node, so summing + // across nodes gives the physical footprint. for _, ecShardInfo := range diskInfo.EcShardInfos { for _, shardSize := range ecShardInfo.ShardSizes { totalSize += shardSize } - if ecShardInfo.FileCount > ecFile[ecShardInfo.Id] { - ecFile[ecShardInfo.Id] = ecShardInfo.FileCount - } - ecDel[ecShardInfo.Id] += ecShardInfo.DeleteCount } } @@ -214,7 +197,6 @@ func (s *AdminServer) getTopologyViaGRPC(topology *ClusterTopology) error { rackObj.Nodes = append(rackObj.Nodes, vs) topology.VolumeServers = append(topology.VolumeServers, vs) topology.TotalVolumes += vs.Volumes - topology.TotalFiles += totalFiles topology.TotalSize += totalSize } @@ -224,17 +206,10 @@ func (s *AdminServer) getTopologyViaGRPC(topology *ClusterTopology) error { topology.DataCenters = append(topology.DataCenters, dataCenter) } - // Fold deduped EC file counts into the cluster total so the - // dashboard header does not drop after volumes are converted - // to erasure coding. - for vid, fc := range ecFile { - dc := ecDel[vid] - if fc >= dc { - topology.TotalFiles += int64(fc - dc) - } else { - glog.Warningf("ec volume %d: summed delete_count=%d exceeds file_count=%d; skipping from TotalFiles", vid, dc, fc) - } - } + // Chunk counts come from the shared collection aggregation, which + // nets out tombstones and counts a chunk once no matter how many + // volume replicas or EC shard holders report it. + topology.TotalChunks = totalCollectionFileCount(resp.TopologyInfo) } return nil diff --git a/weed/admin/dash/collect_collection_stats_test.go b/weed/admin/dash/collect_collection_stats_test.go index d52465612..5451ba636 100644 --- a/weed/admin/dash/collect_collection_stats_test.go +++ b/weed/admin/dash/collect_collection_stats_test.go @@ -235,3 +235,96 @@ func TestCollectCollectionStatsECFileCountMaxDedupe(t *testing.T) { t.Errorf("FileCount: got %d, want 6 (max across reporters)", got.FileCount) } } + +// TestTotalCollectionFileCount verifies the cluster-wide chunk count counts a +// chunk once per replicated volume and per EC volume, and nets out deletes. +func TestTotalCollectionFileCount(t *testing.T) { + // Volume 1 has replication 001 (two copies), so both nodes report the same + // 101 chunks with 10 deleted: 91 live chunks in total, not 182 and not the + // 90 that halving each report would give. + replica := func() *master_pb.DiskInfo { + return &master_pb.DiskInfo{ + VolumeInfos: []*master_pb.VolumeInformationMessage{ + { + Id: 1, + Collection: "bucket-a", + ReplicaPlacement: 1, + FileCount: 101, + DeleteCount: 10, + }, + }, + } + } + // EC volume 2 has its 20 chunks reported by every shard holder. + ecShards := func(bits uint32, sizes []int64) *master_pb.DiskInfo { + return &master_pb.DiskInfo{ + EcShardInfos: []*master_pb.VolumeEcShardInformationMessage{ + { + Id: 2, + Collection: "bucket-b", + EcIndexBits: bits, + ShardSizes: sizes, + FileCount: 20, + }, + }, + } + } + + topo := &master_pb.TopologyInfo{ + DataCenterInfos: []*master_pb.DataCenterInfo{ + { + RackInfos: []*master_pb.RackInfo{ + { + DataNodeInfos: []*master_pb.DataNodeInfo{ + {DiskInfos: map[string]*master_pb.DiskInfo{ + "disk1": replica(), + "disk2": ecShards((1<<0)|(1<<1), []int64{1, 1}), + }}, + {DiskInfos: map[string]*master_pb.DiskInfo{ + "disk1": replica(), + "disk2": ecShards((1<<2)|(1<<3), []int64{1, 1}), + }}, + }, + }, + }, + }, + }, + } + + if got := totalCollectionFileCount(topo); got != 111 { + t.Errorf("totalCollectionFileCount: got %d, want 111 (91 replicated + 20 EC)", got) + } +} + +// TestTotalCollectionFileCountUnderReplicated verifies a volume whose second +// replica has not reported yet still contributes its full live count. +func TestTotalCollectionFileCountUnderReplicated(t *testing.T) { + topo := &master_pb.TopologyInfo{ + DataCenterInfos: []*master_pb.DataCenterInfo{ + { + RackInfos: []*master_pb.RackInfo{ + { + DataNodeInfos: []*master_pb.DataNodeInfo{ + {DiskInfos: map[string]*master_pb.DiskInfo{ + "disk1": { + VolumeInfos: []*master_pb.VolumeInformationMessage{ + { + Id: 1, + Collection: "bucket-a", + ReplicaPlacement: 1, + FileCount: 50, + }, + }, + }, + }}, + }, + }, + }, + }, + }, + } + + if got := totalCollectionFileCount(topo); got != 50 { + t.Errorf("totalCollectionFileCount: got %d, want 50 (one replica reporting, not halved)", got) + } +} diff --git a/weed/admin/dash/collection_management.go b/weed/admin/dash/collection_management.go index 03c1e452b..fe55cf402 100644 --- a/weed/admin/dash/collection_management.go +++ b/weed/admin/dash/collection_management.go @@ -13,7 +13,7 @@ func (s *AdminServer) GetClusterCollections() (*ClusterCollectionsData, error) { var collections []CollectionInfo var totalVolumes int var totalEcVolumes int - var totalFiles int64 + var totalChunks int64 var totalSize int64 collectionMap := make(map[string]*CollectionInfo) @@ -46,7 +46,6 @@ func (s *AdminServer) GetClusterCollections() (*ClusterCollectionsData, error) { // Get or create collection info if collection, exists := collectionMap[collectionName]; exists { collection.VolumeCount++ - collection.FileCount += int64(volInfo.FileCount) collection.TotalSize += int64(volInfo.Size) // Update data center if this collection spans multiple DCs @@ -67,7 +66,6 @@ func (s *AdminServer) GetClusterCollections() (*ClusterCollectionsData, error) { } totalVolumes++ - totalFiles += int64(volInfo.FileCount) totalSize += int64(volInfo.Size) } else { newCollection := CollectionInfo{ @@ -75,13 +73,11 @@ func (s *AdminServer) GetClusterCollections() (*ClusterCollectionsData, error) { DataCenter: dc.Id, VolumeCount: 1, EcVolumeCount: 0, - FileCount: int64(volInfo.FileCount), TotalSize: int64(volInfo.Size), DiskTypes: []string{diskType}, } collectionMap[collectionName] = &newCollection totalVolumes++ - totalFiles += int64(volInfo.FileCount) totalSize += int64(volInfo.Size) } } @@ -133,7 +129,6 @@ func (s *AdminServer) GetClusterCollections() (*ClusterCollectionsData, error) { DataCenter: dc.Id, VolumeCount: 0, EcVolumeCount: 1, - FileCount: 0, TotalSize: 0, DiskTypes: []string{diskType}, } @@ -146,6 +141,16 @@ func (s *AdminServer) GetClusterCollections() (*ClusterCollectionsData, error) { } } } + + // Chunk counts come from the shared collection aggregation, which + // nets out tombstones and counts a chunk once no matter how many + // volume replicas or EC shard holders report it. + for collectionName, stats := range collectCollectionStats(resp.TopologyInfo) { + if collection, exists := collectionMap[collectionName]; exists { + collection.ChunkCount = stats.FileCount + totalChunks += stats.FileCount + } + } } return nil @@ -173,7 +178,7 @@ func (s *AdminServer) GetClusterCollections() (*ClusterCollectionsData, error) { TotalCollections: 0, TotalVolumes: 0, TotalEcVolumes: 0, - TotalFiles: 0, + TotalChunks: 0, TotalSize: 0, LastUpdated: time.Now(), }, nil @@ -184,7 +189,7 @@ func (s *AdminServer) GetClusterCollections() (*ClusterCollectionsData, error) { TotalCollections: len(collections), TotalVolumes: totalVolumes, TotalEcVolumes: totalEcVolumes, - TotalFiles: totalFiles, + TotalChunks: totalChunks, TotalSize: totalSize, LastUpdated: time.Now(), }, nil @@ -208,7 +213,6 @@ func (s *AdminServer) GetCollectionDetails(collectionName string, page int, page var regularVolumes []VolumeWithTopology var ecVolumes []EcVolumeWithShards - var totalFiles int64 var totalSize int64 dataCenters := make(map[string]bool) diskTypes := make(map[string]bool) @@ -222,10 +226,15 @@ func (s *AdminServer) GetCollectionDetails(collectionName string, page int, page regularVolumes = regularVolumeData.Volumes totalSize = regularVolumeData.TotalSize - // Calculate total files from regular volumes - for _, vol := range regularVolumes { - totalFiles += int64(vol.FileCount) + // Chunk counts come from the shared collection aggregation, which nets out + // tombstones and counts a chunk once no matter how many volume replicas or + // EC shard holders report it. Fail rather than render a zero that reads + // like an empty collection. + stats, err := s.getCollectionStats() + if err != nil { + return nil, err } + totalChunks := stats[collectionName].FileCount // Collect data centers and disk types from regular volumes for _, vol := range regularVolumes { @@ -371,7 +380,7 @@ func (s *AdminServer) GetCollectionDetails(collectionName string, page int, page EcVolumes: paginatedEcVolumes, TotalVolumes: len(regularVolumes), TotalEcVolumes: len(ecVolumes), - TotalFiles: totalFiles, + TotalChunks: totalChunks, TotalSize: totalSize, DataCenters: dcList, DiskTypes: diskTypeList, diff --git a/weed/admin/dash/dashboard_metrics.go b/weed/admin/dash/dashboard_metrics.go index 952da432e..be208354d 100644 --- a/weed/admin/dash/dashboard_metrics.go +++ b/weed/admin/dash/dashboard_metrics.go @@ -18,7 +18,7 @@ type dashSample struct { volumes float64 ecShards float64 diskUsed float64 - files float64 + chunks float64 tasks float64 // pending/assigned/in-progress maintenance tasks workers float64 } @@ -33,7 +33,7 @@ type DashboardTrends struct { // Sparklines (raw ) for the existing summary cards. Volumes string `json:"-"` - Files string `json:"-"` + Chunks string `json:"-"` DiskUsed string `json:"-"` EcShards string `json:"-"` @@ -61,7 +61,7 @@ func (s *AdminServer) recordDashboardSample() { volumes: float64(topology.TotalVolumes), ecShards: float64(ecShards), diskUsed: float64(topology.TotalSize), - files: float64(topology.TotalFiles), + chunks: float64(topology.TotalChunks), } if s.maintenanceManager != nil { if stats := s.maintenanceManager.GetStats(); stats != nil { @@ -106,7 +106,7 @@ func (s *AdminServer) GetDashboardTrends() DashboardTrends { return DashboardTrends{ Samples: len(samples), Volumes: sparklineSVG(series(func(s dashSample) float64 { return s.volumes }), "#1cc88a"), // success - Files: sparklineSVG(series(func(s dashSample) float64 { return s.files }), "#36b9cc"), // info + Chunks: sparklineSVG(series(func(s dashSample) float64 { return s.chunks }), "#36b9cc"), // info DiskUsed: sparklineSVG(series(func(s dashSample) float64 { return s.diskUsed }), "#f6c23e"), // warning EcShards: sparklineSVG(series(func(s dashSample) float64 { return s.ecShards }), "#5a5c69"), // dark Tasks: sparklineSVG(tasks, "#36b9cc"), diff --git a/weed/admin/dash/types.go b/weed/admin/dash/types.go index 322fa89dd..6fb8f55c6 100644 --- a/weed/admin/dash/types.go +++ b/weed/admin/dash/types.go @@ -14,9 +14,11 @@ type ClusterTopology struct { DataCenters []DataCenter `json:"datacenters"` VolumeServers []VolumeServer `json:"volume_servers"` TotalVolumes int `json:"total_volumes"` - TotalFiles int64 `json:"total_files"` - TotalSize int64 `json:"total_size"` - UpdatedAt time.Time `json:"updated_at"` + // TotalChunks counts chunks stored in volumes, not filer entries: a file + // is split into one or more chunks. + TotalChunks int64 `json:"total_chunks"` + TotalSize int64 `json:"total_size"` + UpdatedAt time.Time `json:"updated_at"` } type MasterNode struct { @@ -274,7 +276,7 @@ type CollectionInfo struct { DataCenter string `json:"datacenter"` VolumeCount int `json:"volume_count"` EcVolumeCount int `json:"ec_volume_count"` - FileCount int64 `json:"file_count"` + ChunkCount int64 `json:"chunk_count"` TotalSize int64 `json:"total_size"` DiskTypes []string `json:"disk_types"` } @@ -285,7 +287,7 @@ type ClusterCollectionsData struct { TotalCollections int `json:"total_collections"` TotalVolumes int `json:"total_volumes"` TotalEcVolumes int `json:"total_ec_volumes"` - TotalFiles int64 `json:"total_files"` + TotalChunks int64 `json:"total_chunks"` TotalSize int64 `json:"total_size"` LastUpdated time.Time `json:"last_updated"` } @@ -588,7 +590,7 @@ type CollectionDetailsData struct { EcVolumes []EcVolumeWithShards `json:"ec_volumes"` TotalVolumes int `json:"total_volumes"` TotalEcVolumes int `json:"total_ec_volumes"` - TotalFiles int64 `json:"total_files"` + TotalChunks int64 `json:"total_chunks"` TotalSize int64 `json:"total_size"` DataCenters []string `json:"data_centers"` DiskTypes []string `json:"disk_types"` diff --git a/weed/admin/handlers/admin_handlers.go b/weed/admin/handlers/admin_handlers.go index 842ba8b69..73029f260 100644 --- a/weed/admin/handlers/admin_handlers.go +++ b/weed/admin/handlers/admin_handlers.go @@ -577,7 +577,7 @@ func (h *AdminHandlers) getAdminData(r *http.Request) dash.AdminData { return dash.AdminData{ Username: username, TotalVolumes: 0, - TotalFiles: 0, + TotalChunks: 0, TotalSize: 0, MasterNodes: masterNodes, VolumeServers: []dash.VolumeServer{}, diff --git a/weed/admin/view/app/admin.templ b/weed/admin/view/app/admin.templ index 414d859bc..43346d0c0 100644 --- a/weed/admin/view/app/admin.templ +++ b/weed/admin/view/app/admin.templ @@ -50,18 +50,18 @@ templ Admin(data dash.AdminData) {
-
- Total Files +
+ Total Chunks
- {formatNumber(data.TotalFiles)} + {formatNumber(data.TotalChunks)}
- +
- @templ.Raw(data.Trends.Files) + @templ.Raw(data.Trends.Chunks)
diff --git a/weed/admin/view/app/admin_templ.go b/weed/admin/view/app/admin_templ.go index f4bec0d56..0a05cc042 100644 --- a/weed/admin/view/app/admin_templ.go +++ b/weed/admin/view/app/admin_templ.go @@ -1,6 +1,6 @@ // Code generated by templ - DO NOT EDIT. -// templ: version: v0.3.1001 +// templ: version: v0.3.1020 package app //lint:file-ignore SA4006 This context is only used if a nested component is present. @@ -68,24 +68,24 @@ func Admin(data dash.AdminData) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "
Total Files
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "
Total Chunks
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var4 string - templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(formatNumber(data.TotalFiles)) + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(formatNumber(data.TotalChunks)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/admin.templ`, Line: 57, Col: 66} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/admin.templ`, Line: 57, Col: 67} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templ.Raw(data.Trends.Files).Render(ctx, templ_7745c5c3_Buffer) + templ_7745c5c3_Err = templ.Raw(data.Trends.Chunks).Render(ctx, templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/weed/admin/view/app/cluster_collections.templ b/weed/admin/view/app/cluster_collections.templ index 657b37374..e8a6d348a 100644 --- a/weed/admin/view/app/cluster_collections.templ +++ b/weed/admin/view/app/cluster_collections.templ @@ -87,15 +87,15 @@ templ ClusterCollections(data dash.ClusterCollectionsData) {
-
- Total Files +
+ Total Chunks
- {fmt.Sprintf("%d", data.TotalFiles)} + {fmt.Sprintf("%d", data.TotalChunks)}
- +
@@ -139,7 +139,7 @@ templ ClusterCollections(data dash.ClusterCollectionsData) { Collection Name Regular Volumes EC Volumes - Files + Chunks Size (Logical) Disk Types Actions @@ -179,8 +179,8 @@ templ ClusterCollections(data dash.ClusterCollectionsData) {
- - {fmt.Sprintf("%d", collection.FileCount)} + + {fmt.Sprintf("%d", collection.ChunkCount)}
@@ -209,7 +209,7 @@ templ ClusterCollections(data dash.ClusterCollectionsData) { data-datacenter={collection.DataCenter} data-volume-count={fmt.Sprintf("%d", collection.VolumeCount)} data-ec-volume-count={fmt.Sprintf("%d", collection.EcVolumeCount)} - data-file-count={fmt.Sprintf("%d", collection.FileCount)} + data-chunk-count={fmt.Sprintf("%d", collection.ChunkCount)} data-total-size={fmt.Sprintf("%d", collection.TotalSize)} data-disk-types={formatDiskTypes(collection.DiskTypes)}> @@ -262,7 +262,7 @@ templ ClusterCollections(data dash.ClusterCollectionsData) { datacenter: button.getAttribute('data-datacenter'), volumeCount: parseInt(button.getAttribute('data-volume-count')), ecVolumeCount: parseInt(button.getAttribute('data-ec-volume-count')), - fileCount: parseInt(button.getAttribute('data-file-count')), + chunkCount: parseInt(button.getAttribute('data-chunk-count')), totalSize: parseInt(button.getAttribute('data-total-size')), diskTypes: button.getAttribute('data-disk-types') }; @@ -311,10 +311,10 @@ templ ClusterCollections(data dash.ClusterCollectionsData) { '' + collection.ecVolumeCount.toLocaleString() + '' + '
' + '' + - 'Total Files:' + + 'Total Chunks:' + '
' + - '' + - '' + collection.fileCount.toLocaleString() + '' + + '' + + '' + collection.chunkCount.toLocaleString() + '' + '
' + '' + 'Total Size (Logical):' + @@ -396,17 +396,18 @@ templ ClusterCollections(data dash.ClusterCollectionsData) { return { name: cells[0].textContent.trim(), volumes: cells[1].textContent.trim(), - files: cells[2].textContent.trim(), - size: cells[3].textContent.trim(), - diskTypes: cells[4].textContent.trim() + ecVolumes: cells[2].textContent.trim(), + chunks: cells[3].textContent.trim(), + size: cells[4].textContent.trim(), + diskTypes: cells[5].textContent.trim() }; } return null; }).filter(row => row !== null); - - const csvContent = "data:text/csv;charset=utf-8," + - "Collection Name,Volumes,Files,Size,Disk Types\n" + - rows.map(r => '"' + r.name + '","' + r.volumes + '","' + r.files + '","' + r.size + '","' + r.diskTypes + '"').join("\n"); + + const csvContent = "data:text/csv;charset=utf-8," + + "Collection Name,Volumes,EC Volumes,Chunks,Size,Disk Types\n" + + rows.map(r => '"' + r.name + '","' + r.volumes + '","' + r.ecVolumes + '","' + r.chunks + '","' + r.size + '","' + r.diskTypes + '"').join("\n"); const encodedUri = encodeURI(csvContent); const link = document.createElement("a"); diff --git a/weed/admin/view/app/cluster_collections_templ.go b/weed/admin/view/app/cluster_collections_templ.go index bedff8916..008078b01 100644 --- a/weed/admin/view/app/cluster_collections_templ.go +++ b/weed/admin/view/app/cluster_collections_templ.go @@ -1,6 +1,6 @@ // Code generated by templ - DO NOT EDIT. -// templ: version: v0.3.1001 +// templ: version: v0.3.1020 package app //lint:file-ignore SA4006 This context is only used if a nested component is present. @@ -73,20 +73,20 @@ func ClusterCollections(data dash.ClusterCollectionsData) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "
Total Files
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "
Total Chunks
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var5 string - templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", data.TotalFiles)) + templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", data.TotalChunks)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_collections.templ`, Line: 94, Col: 71} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_collections.templ`, Line: 94, Col: 72} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "
Total Storage Size (Logical)
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "
Total Storage Size (Logical)
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -104,7 +104,7 @@ func ClusterCollections(data dash.ClusterCollectionsData) templ.Component { return templ_7745c5c3_Err } if len(data.Collections) > 0 { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "
Collection NameRegular VolumesEC VolumesFilesSize (Logical)Disk TypesActions
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -201,14 +201,14 @@ func ClusterCollections(data dash.ClusterCollectionsData) templ.Component { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, " - + diff --git a/weed/admin/view/app/collection_details_templ.go b/weed/admin/view/app/collection_details_templ.go index d017ca932..d3be97a9a 100644 --- a/weed/admin/view/app/collection_details_templ.go +++ b/weed/admin/view/app/collection_details_templ.go @@ -1,6 +1,6 @@ // Code generated by templ - DO NOT EDIT. -// templ: version: v0.3.1001 +// templ: version: v0.3.1020 package app //lint:file-ignore SA4006 This context is only used if a nested component is present. @@ -113,20 +113,20 @@ func CollectionDetails(data dash.CollectionDetailsData) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "Erasure coded volumes
Total Files

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "

Erasure coded volumes
Total Chunks

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var8 string - templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", data.TotalFiles)) + templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", data.TotalChunks)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/collection_details.templ`, Line: 75, Col: 59} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/collection_details.templ`, Line: 75, Col: 60} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "

Files stored
Total Size (Logical)

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "

A file is split into one or more chunks
Total Size (Logical)

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -269,7 +269,7 @@ func CollectionDetails(data dash.CollectionDetailsData) templ.Component { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -333,11 +333,11 @@ func CollectionDetails(data dash.CollectionDetailsData) templ.Component { return templ_7745c5c3_Err } var templ_7745c5c3_Var16 string - templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", volume.Id)) + templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.ResolveAttributeValue(fmt.Sprintf("%d", volume.Id)) if templ_7745c5c3_Err != nil { return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/collection_details.templ`, Line: 206, Col: 55} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var16) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -346,11 +346,11 @@ func CollectionDetails(data dash.CollectionDetailsData) templ.Component { return templ_7745c5c3_Err } var templ_7745c5c3_Var17 string - templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(volume.Server) + templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.ResolveAttributeValue(volume.Server) if templ_7745c5c3_Err != nil { return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/collection_details.templ`, Line: 207, Col: 37} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var17) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -419,11 +419,11 @@ func CollectionDetails(data dash.CollectionDetailsData) templ.Component { return templ_7745c5c3_Err } var templ_7745c5c3_Var21 string - templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", ecVolume.VolumeID)) + templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.ResolveAttributeValue(fmt.Sprintf("%d", ecVolume.VolumeID)) if templ_7745c5c3_Err != nil { return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/collection_details.templ`, Line: 249, Col: 63} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var21) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -466,11 +466,11 @@ func CollectionDetails(data dash.CollectionDetailsData) templ.Component { return templ_7745c5c3_Err } var templ_7745c5c3_Var23 string - templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", data.Page-1)) + templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.ResolveAttributeValue(fmt.Sprintf("%d", data.Page-1)) if templ_7745c5c3_Err != nil { return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/collection_details.templ`, Line: 280, Col: 104} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var23) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -504,11 +504,11 @@ func CollectionDetails(data dash.CollectionDetailsData) templ.Component { return templ_7745c5c3_Err } var templ_7745c5c3_Var25 string - templ_7745c5c3_Var25, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", i)) + templ_7745c5c3_Var25, templ_7745c5c3_Err = templ.ResolveAttributeValue(fmt.Sprintf("%d", i)) if templ_7745c5c3_Err != nil { return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/collection_details.templ`, Line: 291, Col: 95} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var25)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var25) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -547,11 +547,11 @@ func CollectionDetails(data dash.CollectionDetailsData) templ.Component { return templ_7745c5c3_Err } var templ_7745c5c3_Var27 string - templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", data.Page+1)) + templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.ResolveAttributeValue(fmt.Sprintf("%d", data.Page+1)) if templ_7745c5c3_Err != nil { return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/collection_details.templ`, Line: 306, Col: 104} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var27)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var27) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -560,11 +560,11 @@ func CollectionDetails(data dash.CollectionDetailsData) templ.Component { return templ_7745c5c3_Err } var templ_7745c5c3_Var28 string - templ_7745c5c3_Var28, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", data.TotalPages)) + templ_7745c5c3_Var28, templ_7745c5c3_Err = templ.ResolveAttributeValue(fmt.Sprintf("%d", data.TotalPages)) if templ_7745c5c3_Err != nil { return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/collection_details.templ`, Line: 309, Col: 108} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var28)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var28) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err }
Collection NameRegular VolumesEC VolumesChunksSize (Logical)Disk TypesActions
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var13 string - templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", collection.FileCount)) + templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", collection.ChunkCount)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_collections.templ`, Line: 183, Col: 88} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_collections.templ`, Line: 183, Col: 89} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13)) if templ_7745c5c3_Err != nil { @@ -252,11 +252,11 @@ func ClusterCollections(data dash.ClusterCollectionsData) templ.Component { return templ_7745c5c3_Err } var templ_7745c5c3_Var16 string - templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var15).String()) + templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var15).String()) if templ_7745c5c3_Err != nil { return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_collections.templ`, Line: 1, Col: 0} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var16) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -289,11 +289,11 @@ func ClusterCollections(data dash.ClusterCollectionsData) templ.Component { return templ_7745c5c3_Err } var templ_7745c5c3_Var18 string - templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(collection.Name) + templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.ResolveAttributeValue(collection.Name) if templ_7745c5c3_Err != nil { return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_collections.templ`, Line: 208, Col: 78} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var18) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -302,11 +302,11 @@ func ClusterCollections(data dash.ClusterCollectionsData) templ.Component { return templ_7745c5c3_Err } var templ_7745c5c3_Var19 string - templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(collection.DataCenter) + templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.ResolveAttributeValue(collection.DataCenter) if templ_7745c5c3_Err != nil { return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_collections.templ`, Line: 209, Col: 90} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var19) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -315,11 +315,11 @@ func ClusterCollections(data dash.ClusterCollectionsData) templ.Component { return templ_7745c5c3_Err } var templ_7745c5c3_Var20 string - templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", collection.VolumeCount)) + templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.ResolveAttributeValue(fmt.Sprintf("%d", collection.VolumeCount)) if templ_7745c5c3_Err != nil { return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_collections.templ`, Line: 210, Col: 112} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var20) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -328,24 +328,24 @@ func ClusterCollections(data dash.ClusterCollectionsData) templ.Component { return templ_7745c5c3_Err } var templ_7745c5c3_Var21 string - templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", collection.EcVolumeCount)) + templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.ResolveAttributeValue(fmt.Sprintf("%d", collection.EcVolumeCount)) if templ_7745c5c3_Err != nil { return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_collections.templ`, Line: 211, Col: 117} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var21) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "\" data-file-count=\"") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "\" data-chunk-count=\"") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var22 string - templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", collection.FileCount)) + templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.ResolveAttributeValue(fmt.Sprintf("%d", collection.ChunkCount)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_collections.templ`, Line: 212, Col: 108} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_collections.templ`, Line: 212, Col: 110} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var22) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -354,11 +354,11 @@ func ClusterCollections(data dash.ClusterCollectionsData) templ.Component { return templ_7745c5c3_Err } var templ_7745c5c3_Var23 string - templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", collection.TotalSize)) + templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.ResolveAttributeValue(fmt.Sprintf("%d", collection.TotalSize)) if templ_7745c5c3_Err != nil { return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_collections.templ`, Line: 213, Col: 108} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var23) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -367,11 +367,11 @@ func ClusterCollections(data dash.ClusterCollectionsData) templ.Component { return templ_7745c5c3_Err } var templ_7745c5c3_Var24 string - templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.JoinStringErrs(formatDiskTypes(collection.DiskTypes)) + templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.ResolveAttributeValue(formatDiskTypes(collection.DiskTypes)) if templ_7745c5c3_Err != nil { return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_collections.templ`, Line: 214, Col: 106} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var24)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var24) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -403,7 +403,7 @@ func ClusterCollections(data dash.ClusterCollectionsData) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/weed/admin/view/app/collection_details.templ b/weed/admin/view/app/collection_details.templ index 7e73d278a..c48a4e48a 100644 --- a/weed/admin/view/app/collection_details.templ +++ b/weed/admin/view/app/collection_details.templ @@ -71,12 +71,12 @@ templ CollectionDetails(data dash.CollectionDetailsData) {
-
Total Files
-

{fmt.Sprintf("%d", data.TotalFiles)}

- Files stored +
Total Chunks
+

{fmt.Sprintf("%d", data.TotalChunks)}

+ A file is split into one or more chunks
- +
@@ -169,7 +169,7 @@ templ CollectionDetails(data dash.CollectionDetailsData) {
Logical Size / Shard CountFilesChunks Status Actions
Logical Size / Shard CountFilesStatusActions
Logical Size / Shard CountChunksStatusActions