Add extended dashboard metrics and helpers
Extend FetchDashboardData to collect additional metrics: tool executions, addon installations, GPU usage (including passthrough), error categories, and install durations for averaging. Populate new Dashboard fields (GPUStats, ErrorCategories, TopTools, TopAddons, AvgInstallDuration) and add helper builders (buildGPUStats, buildErrorCategories, buildToolStats, buildAddonStats) that sort results and trim to top-N where appropriate. Keeps existing daily stats and recent records logic unchanged.
This commit is contained in:
parent
182bf36346
commit
ed3af96585
@ -191,6 +191,40 @@ func (p *PBClient) FetchDashboardData(ctx context.Context, days int) (*Dashboard
|
||||
typeCounts[r.Type]++
|
||||
}
|
||||
|
||||
// === Extended metrics tracking ===
|
||||
|
||||
// Track tool executions
|
||||
if r.Type == "tool" && r.ToolName != "" {
|
||||
toolCounts[r.ToolName]++
|
||||
data.TotalTools++
|
||||
}
|
||||
|
||||
// Track addon installations
|
||||
if r.Type == "addon" {
|
||||
addonCounts[r.NSAPP]++
|
||||
data.TotalAddons++
|
||||
}
|
||||
|
||||
// Track GPU usage
|
||||
if r.GPUVendor != "" {
|
||||
key := r.GPUVendor
|
||||
if r.GPUPassthrough != "" {
|
||||
key += "|" + r.GPUPassthrough
|
||||
}
|
||||
gpuCounts[key]++
|
||||
}
|
||||
|
||||
// Track error categories
|
||||
if r.Status == "failed" && r.ErrorCategory != "" {
|
||||
errorCatCounts[r.ErrorCategory]++
|
||||
}
|
||||
|
||||
// Track install duration (for averaging)
|
||||
if r.InstallDuration > 0 {
|
||||
totalDuration += r.InstallDuration
|
||||
durationCount++
|
||||
}
|
||||
|
||||
// Daily stats (use Created field if available)
|
||||
if r.Created != "" {
|
||||
date := r.Created[:10] // "2026-02-09"
|
||||
@ -224,6 +258,25 @@ func (p *PBClient) FetchDashboardData(ctx context.Context, days int) (*Dashboard
|
||||
// Daily stats for chart
|
||||
data.DailyStats = buildDailyStats(dailySuccess, dailyFailed, days)
|
||||
|
||||
// === Extended metrics ===
|
||||
|
||||
// GPU stats
|
||||
data.GPUStats = buildGPUStats(gpuCounts)
|
||||
|
||||
// Error categories
|
||||
data.ErrorCategories = buildErrorCategories(errorCatCounts)
|
||||
|
||||
// Top tools
|
||||
data.TopTools = buildToolStats(toolCounts, 10)
|
||||
|
||||
// Top addons
|
||||
data.TopAddons = buildAddonStats(addonCounts, 10)
|
||||
|
||||
// Average install duration
|
||||
if durationCount > 0 {
|
||||
data.AvgInstallDuration = float64(totalDuration) / float64(durationCount)
|
||||
}
|
||||
|
||||
// Recent records (last 20)
|
||||
if len(records) > 20 {
|
||||
data.RecentRecords = records[:20]
|
||||
@ -502,6 +555,97 @@ func buildDailyStats(success, failed map[string]int, days int) []DailyStat {
|
||||
return result
|
||||
}
|
||||
|
||||
// === Extended metrics helper functions ===
|
||||
|
||||
func buildGPUStats(gpuCounts map[string]int) []GPUCount {
|
||||
result := make([]GPUCount, 0, len(gpuCounts))
|
||||
for key, count := range gpuCounts {
|
||||
parts := strings.Split(key, "|")
|
||||
vendor := parts[0]
|
||||
passthrough := ""
|
||||
if len(parts) > 1 {
|
||||
passthrough = parts[1]
|
||||
}
|
||||
result = append(result, GPUCount{
|
||||
Vendor: vendor,
|
||||
Passthrough: passthrough,
|
||||
Count: count,
|
||||
})
|
||||
}
|
||||
// Sort by count descending
|
||||
for i := 0; i < len(result)-1; i++ {
|
||||
for j := i + 1; j < len(result); j++ {
|
||||
if result[j].Count > result[i].Count {
|
||||
result[i], result[j] = result[j], result[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func buildErrorCategories(catCounts map[string]int) []ErrorCatCount {
|
||||
result := make([]ErrorCatCount, 0, len(catCounts))
|
||||
for cat, count := range catCounts {
|
||||
result = append(result, ErrorCatCount{
|
||||
Category: cat,
|
||||
Count: count,
|
||||
})
|
||||
}
|
||||
// Sort by count descending
|
||||
for i := 0; i < len(result)-1; i++ {
|
||||
for j := i + 1; j < len(result); j++ {
|
||||
if result[j].Count > result[i].Count {
|
||||
result[i], result[j] = result[j], result[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func buildToolStats(toolCounts map[string]int, n int) []ToolCount {
|
||||
result := make([]ToolCount, 0, len(toolCounts))
|
||||
for tool, count := range toolCounts {
|
||||
result = append(result, ToolCount{
|
||||
Tool: tool,
|
||||
Count: count,
|
||||
})
|
||||
}
|
||||
// Sort by count descending
|
||||
for i := 0; i < len(result)-1; i++ {
|
||||
for j := i + 1; j < len(result); j++ {
|
||||
if result[j].Count > result[i].Count {
|
||||
result[i], result[j] = result[j], result[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(result) > n {
|
||||
return result[:n]
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func buildAddonStats(addonCounts map[string]int, n int) []AddonCount {
|
||||
result := make([]AddonCount, 0, len(addonCounts))
|
||||
for addon, count := range addonCounts {
|
||||
result = append(result, AddonCount{
|
||||
Addon: addon,
|
||||
Count: count,
|
||||
})
|
||||
}
|
||||
// Sort by count descending
|
||||
for i := 0; i < len(result)-1; i++ {
|
||||
for j := i + 1; j < len(result); j++ {
|
||||
if result[j].Count > result[i].Count {
|
||||
result[i], result[j] = result[j], result[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(result) > n {
|
||||
return result[:n]
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// DashboardHTML returns the embedded dashboard HTML
|
||||
func DashboardHTML() string {
|
||||
return `<!DOCTYPE html>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user