internal/httpd/activity.go
66 lines · 1719 bytes
1package httpd
2
3import (
4 "time"
5
6 "gitbay.org/gitbay/internal/control"
7)
8
9// activityDay is one cell of the graph; Level buckets Count into the five
10// intensity classes the stylesheet colors.
11type activityDay struct {
12 Date string
13 Count int
14 Level int // 0..4
15 Pad bool // before the range start / after today
16}
17
18type activityWeek []activityDay // 7 days, Sunday first
19
20// activityGrid lays a day->count map into 53 week columns ending today,
21// GitHub-style: columns are weeks, rows Sunday..Saturday.
22func activityGrid(counts map[string]int) ([]activityWeek, int) {
23 today := time.Now().UTC()
24 // End the grid on the Saturday of the current week.
25 end := today.AddDate(0, 0, int(time.Saturday-today.Weekday()))
26 start := end.AddDate(0, 0, -53*7+1) // a Sunday, 53 columns back
27
28 total := 0
29 var weeks []activityWeek
30 for d := start; !d.After(end); d = d.AddDate(0, 0, 7) {
31 var week activityWeek
32 for i := 0; i < 7; i++ {
33 day := d.AddDate(0, 0, i)
34 key := day.Format("2006-01-02")
35 if day.After(today) {
36 week = append(week, activityDay{Date: key, Pad: true})
37 continue
38 }
39 n := counts[key]
40 total += n
41 week = append(week, activityDay{Date: key, Count: n, Level: activityLevel(n)})
42 }
43 weeks = append(weeks, week)
44 }
45 return weeks, total
46}
47
48func activityLevel(n int) int {
49 switch {
50 case n == 0:
51 return 0
52 case n <= 2:
53 return 1
54 case n <= 5:
55 return 2
56 case n <= 9:
57 return 3
58 default:
59 return 4
60 }
61}
62
63// activitySince is the first day the grid can show, for the query bound.
64// activitySince is control.ActivityWindow: the profile command and the
65// web must report the same year, so the span has one definition.
66func activitySince() string { return control.ActivityWindow() }