From 0cf62a921a1a2a67159b1a91694043a2f9e8ddb7 Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Thu, 6 Aug 2026 11:22:06 -0700 Subject: [PATCH] admin: dashboard counts chunks, not files (#10598) * admin: count each chunk once in the dashboard total The dashboard summed file_count from every node's volume list, so a chunk was counted once per replica and deleted chunks were never subtracted. Reuse the collection aggregation, which dedupes replicas and EC shard holders and nets out tombstones. * admin: the dashboard card counts chunks, so name it that Volumes store chunks, and a file is split into one or more of them, so the 'Total Files' card always read far higher than the number of files in the filer. Rename it to 'Total Chunks' and say so in the tooltip. * admin: collections pages count chunks once and say so The collections list and detail pages summed file_count straight off the topology, so replicas multiplied the count, tombstones stayed in it, and the detail page ignored EC volumes entirely. Take the numbers from the shared collection aggregation and label them chunks. * admin: dedupe replica chunk counts per volume instead of dividing Dividing each replica's live count by the copy count truncated a chunk per odd-sized volume, and reported half the count while a volume's second replica had not checked in yet. Replicas mirror each other's needles and deletes, so keep the fullest report per volume id. * admin: fix the collections CSV export column mapping The exporter read chunks from the EC-volume cell and shifted size and disk types with it. Read every column the table actually has. --- weed/admin/dash/admin_data.go | 4 +- weed/admin/dash/admin_server.go | 44 ++++++++- weed/admin/dash/cluster_topology.go | 37 ++------ .../dash/collect_collection_stats_test.go | 93 +++++++++++++++++++ weed/admin/dash/collection_management.go | 35 ++++--- weed/admin/dash/dashboard_metrics.go | 8 +- weed/admin/dash/types.go | 14 +-- weed/admin/handlers/admin_handlers.go | 2 +- weed/admin/view/app/admin.templ | 10 +- weed/admin/view/app/admin_templ.go | 12 +-- weed/admin/view/app/cluster_collections.templ | 39 ++++---- .../view/app/cluster_collections_templ.go | 56 +++++------ weed/admin/view/app/collection_details.templ | 10 +- .../view/app/collection_details_templ.go | 40 ++++---- 14 files changed, 261 insertions(+), 143 deletions(-) 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