P6-03 repo size trend + agent-update UI fix + dashboard polish #21
@@ -284,7 +284,7 @@ func (s *Server) buildRepoTrendView(ctx context.Context, hostID, rangeKey string
|
||||
chartSVG := sparkline.RenderChart([]sparkline.Series{
|
||||
{Name: "size", Stroke: "#3b82f6", Axis: sparkline.AxisLeft, Format: sparkline.FormatBytes, Points: sizes},
|
||||
{Name: "snapshots", Stroke: "#f59e0b", Axis: sparkline.AxisRight, Format: sparkline.FormatCount, Points: counts},
|
||||
}, dayList, sparkline.ChartOpts{Width: 600, Height: 220})
|
||||
}, dayList, sparkline.ChartOpts{Width: 640, Height: 220})
|
||||
return repoTrendView{HostID: hostID, Range: rangeKey, ChartSVG: chartSVG}
|
||||
}
|
||||
|
||||
|
||||
@@ -156,7 +156,7 @@ func RenderChart(series []Series, days []time.Time, opts ChartOpts) template.HTM
|
||||
if opts.EmptyLabel == "" {
|
||||
opts.EmptyLabel = "no data yet"
|
||||
}
|
||||
const padL, padR, padT, padB = 56, 56, 16, 28
|
||||
const padL, padR, padT, padB = 72, 56, 16, 28
|
||||
w, h := opts.Width, opts.Height
|
||||
innerW := w - padL - padR
|
||||
innerH := h - padT - padB
|
||||
@@ -255,6 +255,11 @@ func RenderChart(series []Series, days []time.Time, opts ChartOpts) template.HTM
|
||||
continue
|
||||
}
|
||||
x := float64(padL) + stepX*float64(i)
|
||||
if len(days) == 1 {
|
||||
// Single-day: pin the lone dot to the chart centre so it
|
||||
// sits under the centred date label.
|
||||
x = float64(padL) + float64(innerW)/2
|
||||
}
|
||||
y := float64(padT) + float64(innerH) - (v-a.min)/(a.max-a.min)*float64(innerH)
|
||||
fmt.Fprintf(&seg, "%.2f,%.2f ", x, y)
|
||||
d := days[i]
|
||||
@@ -267,18 +272,48 @@ func RenderChart(series []Series, days []time.Time, opts ChartOpts) template.HTM
|
||||
|
||||
if axArr[AxisLeft].has {
|
||||
writeAxisLabels(&b, padL-6, padT, innerH, axArr[AxisLeft].min, axArr[AxisLeft].max, FormatBytes, "end")
|
||||
// Rotated axis title in the left margin. Position inset from
|
||||
// the viewBox edge by ≈ font-size so the rotated glyph extents
|
||||
// don't clip against the SVG boundary.
|
||||
cy := padT + innerH/2
|
||||
fmt.Fprintf(&b,
|
||||
`<text x="14" y="%d" text-anchor="middle" font-size="11" fill="currentColor" fill-opacity="0.55" transform="rotate(-90, 14, %d)">Size</text>`,
|
||||
cy, cy)
|
||||
}
|
||||
if axArr[AxisRight].has {
|
||||
writeAxisLabels(&b, w-padR+6, padT, innerH, axArr[AxisRight].min, axArr[AxisRight].max, FormatCount, "start")
|
||||
cy := padT + innerH/2
|
||||
fmt.Fprintf(&b,
|
||||
`<text x="%d" y="%d" text-anchor="middle" font-size="11" fill="currentColor" fill-opacity="0.55" transform="rotate(90, %d, %d)">Snapshots</text>`,
|
||||
w-14, cy, w-14, cy)
|
||||
}
|
||||
|
||||
xLabels := []int{0, len(days) / 2, len(days) - 1}
|
||||
anchors := []string{"start", "middle", "end"}
|
||||
for i, idx := range xLabels {
|
||||
x := float64(padL) + stepX*float64(idx)
|
||||
// X-axis labels at start / mid / end. With 1-2 days the indices
|
||||
// collapse onto each other — dedupe so we don't stack overlapping
|
||||
// "Jan 2" labels at the same x coordinate.
|
||||
type xLabel struct {
|
||||
idx int
|
||||
anchor string
|
||||
}
|
||||
var xLabels []xLabel
|
||||
switch {
|
||||
case len(days) == 1:
|
||||
xLabels = []xLabel{{0, "middle"}}
|
||||
case len(days) == 2:
|
||||
xLabels = []xLabel{{0, "start"}, {1, "end"}}
|
||||
default:
|
||||
xLabels = []xLabel{{0, "start"}, {len(days) / 2, "middle"}, {len(days) - 1, "end"}}
|
||||
}
|
||||
for _, l := range xLabels {
|
||||
x := float64(padL) + stepX*float64(l.idx)
|
||||
// With a single point, anchor "middle" centres on padL — push to
|
||||
// the chart's centre line so the lone label sits over the dot.
|
||||
if len(days) == 1 {
|
||||
x = float64(padL) + float64(innerW)/2
|
||||
}
|
||||
fmt.Fprintf(&b,
|
||||
`<text x="%.2f" y="%d" text-anchor="%s" font-size="10" fill="currentColor" fill-opacity="0.55">%s</text>`,
|
||||
x, h-padB+16, anchors[i], days[idx].Format("Jan 2"))
|
||||
x, h-padB+16, l.anchor, days[l.idx].Format("Jan 2"))
|
||||
}
|
||||
|
||||
b.WriteString(`</svg>`)
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 220" class="repo-trend-chart" role="img" aria-label="repo size and snapshot count over time"><line x1="56" y1="110" x2="544" y2="110" stroke="currentColor" stroke-opacity="0.15" stroke-dasharray="3,3"/><text x="300" y="114" text-anchor="middle" font-size="12" fill="currentColor" fill-opacity="0.4">no data yet</text></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 220" class="repo-trend-chart" role="img" aria-label="repo size and snapshot count over time"><line x1="72" y1="110" x2="544" y2="110" stroke="currentColor" stroke-opacity="0.15" stroke-dasharray="3,3"/><text x="300" y="114" text-anchor="middle" font-size="12" fill="currentColor" fill-opacity="0.4">no data yet</text></svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 381 B After Width: | Height: | Size: 381 B |
+1
-1
@@ -1 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 220" class="repo-trend-chart" role="img" aria-label="repo size and snapshot count over time"><line x1="56" y1="16" x2="544" y2="16" stroke="currentColor" stroke-opacity="0.08"/><line x1="56" y1="60" x2="544" y2="60" stroke="currentColor" stroke-opacity="0.08"/><line x1="56" y1="104" x2="544" y2="104" stroke="currentColor" stroke-opacity="0.08"/><line x1="56" y1="148" x2="544" y2="148" stroke="currentColor" stroke-opacity="0.08"/><line x1="56" y1="192" x2="544" y2="192" stroke="currentColor" stroke-opacity="0.08"/><circle cx="56.00" cy="192.00" r="2.5" fill="#3b82f6"><title>2026-05-01 · size: 1.0 KiB</title></circle><circle cx="218.67" cy="166.86" r="2.5" fill="#3b82f6"><title>2026-05-02 · size: 2.0 KiB</title></circle><circle cx="381.33" cy="116.57" r="2.5" fill="#3b82f6"><title>2026-05-03 · size: 4.0 KiB</title></circle><circle cx="544.00" cy="16.00" r="2.5" fill="#3b82f6"><title>2026-05-04 · size: 8.0 KiB</title></circle><polyline fill="none" stroke="#3b82f6" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" points="56.00,192.00 218.67,166.86 381.33,116.57 544.00,16.00"/><circle cx="56.00" cy="192.00" r="2.5" fill="#f59e0b"><title>2026-05-01 · snapshots: 1</title></circle><circle cx="218.67" cy="133.33" r="2.5" fill="#f59e0b"><title>2026-05-02 · snapshots: 2</title></circle><circle cx="381.33" cy="74.67" r="2.5" fill="#f59e0b"><title>2026-05-03 · snapshots: 3</title></circle><circle cx="544.00" cy="16.00" r="2.5" fill="#f59e0b"><title>2026-05-04 · snapshots: 4</title></circle><polyline fill="none" stroke="#f59e0b" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" points="56.00,192.00 218.67,133.33 381.33,74.67 544.00,16.00"/><text x="50" y="19" text-anchor="end" font-size="10" fill="currentColor" fill-opacity="0.55">8.0 KiB</text><text x="50" y="63" text-anchor="end" font-size="10" fill="currentColor" fill-opacity="0.55">6.2 KiB</text><text x="50" y="107" text-anchor="end" font-size="10" fill="currentColor" fill-opacity="0.55">4.5 KiB</text><text x="50" y="151" text-anchor="end" font-size="10" fill="currentColor" fill-opacity="0.55">2.8 KiB</text><text x="50" y="195" text-anchor="end" font-size="10" fill="currentColor" fill-opacity="0.55">1.0 KiB</text><text x="550" y="19" text-anchor="start" font-size="10" fill="currentColor" fill-opacity="0.55">4</text><text x="550" y="63" text-anchor="start" font-size="10" fill="currentColor" fill-opacity="0.55">3</text><text x="550" y="107" text-anchor="start" font-size="10" fill="currentColor" fill-opacity="0.55">2</text><text x="550" y="151" text-anchor="start" font-size="10" fill="currentColor" fill-opacity="0.55">2</text><text x="550" y="195" text-anchor="start" font-size="10" fill="currentColor" fill-opacity="0.55">1</text><text x="56.00" y="208" text-anchor="start" font-size="10" fill="currentColor" fill-opacity="0.55">May 1</text><text x="381.33" y="208" text-anchor="middle" font-size="10" fill="currentColor" fill-opacity="0.55">May 3</text><text x="544.00" y="208" text-anchor="end" font-size="10" fill="currentColor" fill-opacity="0.55">May 4</text></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 220" class="repo-trend-chart" role="img" aria-label="repo size and snapshot count over time"><line x1="72" y1="16" x2="544" y2="16" stroke="currentColor" stroke-opacity="0.08"/><line x1="72" y1="60" x2="544" y2="60" stroke="currentColor" stroke-opacity="0.08"/><line x1="72" y1="104" x2="544" y2="104" stroke="currentColor" stroke-opacity="0.08"/><line x1="72" y1="148" x2="544" y2="148" stroke="currentColor" stroke-opacity="0.08"/><line x1="72" y1="192" x2="544" y2="192" stroke="currentColor" stroke-opacity="0.08"/><circle cx="72.00" cy="192.00" r="2.5" fill="#3b82f6"><title>2026-05-01 · size: 1.0 KiB</title></circle><circle cx="229.33" cy="166.86" r="2.5" fill="#3b82f6"><title>2026-05-02 · size: 2.0 KiB</title></circle><circle cx="386.67" cy="116.57" r="2.5" fill="#3b82f6"><title>2026-05-03 · size: 4.0 KiB</title></circle><circle cx="544.00" cy="16.00" r="2.5" fill="#3b82f6"><title>2026-05-04 · size: 8.0 KiB</title></circle><polyline fill="none" stroke="#3b82f6" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" points="72.00,192.00 229.33,166.86 386.67,116.57 544.00,16.00"/><circle cx="72.00" cy="192.00" r="2.5" fill="#f59e0b"><title>2026-05-01 · snapshots: 1</title></circle><circle cx="229.33" cy="133.33" r="2.5" fill="#f59e0b"><title>2026-05-02 · snapshots: 2</title></circle><circle cx="386.67" cy="74.67" r="2.5" fill="#f59e0b"><title>2026-05-03 · snapshots: 3</title></circle><circle cx="544.00" cy="16.00" r="2.5" fill="#f59e0b"><title>2026-05-04 · snapshots: 4</title></circle><polyline fill="none" stroke="#f59e0b" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" points="72.00,192.00 229.33,133.33 386.67,74.67 544.00,16.00"/><text x="66" y="19" text-anchor="end" font-size="10" fill="currentColor" fill-opacity="0.55">8.0 KiB</text><text x="66" y="63" text-anchor="end" font-size="10" fill="currentColor" fill-opacity="0.55">6.2 KiB</text><text x="66" y="107" text-anchor="end" font-size="10" fill="currentColor" fill-opacity="0.55">4.5 KiB</text><text x="66" y="151" text-anchor="end" font-size="10" fill="currentColor" fill-opacity="0.55">2.8 KiB</text><text x="66" y="195" text-anchor="end" font-size="10" fill="currentColor" fill-opacity="0.55">1.0 KiB</text><text x="14" y="104" text-anchor="middle" font-size="11" fill="currentColor" fill-opacity="0.55" transform="rotate(-90, 14, 104)">Size</text><text x="550" y="19" text-anchor="start" font-size="10" fill="currentColor" fill-opacity="0.55">4</text><text x="550" y="63" text-anchor="start" font-size="10" fill="currentColor" fill-opacity="0.55">3</text><text x="550" y="107" text-anchor="start" font-size="10" fill="currentColor" fill-opacity="0.55">2</text><text x="550" y="151" text-anchor="start" font-size="10" fill="currentColor" fill-opacity="0.55">2</text><text x="550" y="195" text-anchor="start" font-size="10" fill="currentColor" fill-opacity="0.55">1</text><text x="586" y="104" text-anchor="middle" font-size="11" fill="currentColor" fill-opacity="0.55" transform="rotate(90, 586, 104)">Snapshots</text><text x="72.00" y="208" text-anchor="start" font-size="10" fill="currentColor" fill-opacity="0.55">May 1</text><text x="386.67" y="208" text-anchor="middle" font-size="10" fill="currentColor" fill-opacity="0.55">May 3</text><text x="544.00" y="208" text-anchor="end" font-size="10" fill="currentColor" fill-opacity="0.55">May 4</text></svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.4 KiB |
Reference in New Issue
Block a user