Skip to content

Commit

Permalink
Implement "show fewer numbers"
Browse files Browse the repository at this point in the history
Fixes #533
  • Loading branch information
arp242 committed Oct 19, 2022
1 parent 3fb18bc commit 0f26b42
Show file tree
Hide file tree
Showing 12 changed files with 158 additions and 71 deletions.
34 changes: 25 additions & 9 deletions handlers/settings_user.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,31 +26,47 @@ func (h settings) userPref(verr *zvalidate.Validator) zhttp.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) error {
return zhttp.Template(w, "user_pref.gohtml", struct {
Globals
Validate *zvalidate.Validator
Timezones []*tz.Zone
}{newGlobals(w, r), verr, tz.Zones})
Validate *zvalidate.Validator
Timezones []*tz.Zone
FewerNumbersLocked bool
}{newGlobals(w, r), verr, tz.Zones,
goatcounter.MustGetUser(r.Context()).Settings.FewerNumbersLockUntil.After(ztime.Now())})
}
}

func (h settings) userPrefSave(w http.ResponseWriter, r *http.Request) error {
args := struct {
User goatcounter.User `json:"user"`
SetSite bool `json:"set_site"`
}{*User(r.Context()), false}
User goatcounter.User `json:"user"`
SetSite bool `json:"set_site"`
FewerNumbersLock string `json:"fewer_numbers_lock"`
}{*User(r.Context()), false, ""}
var (
oldEmail = args.User.Email
oldReports = args.User.Settings.EmailReports
oldEmail = args.User.Email
oldReports = args.User.Settings.EmailReports
oldFewerNums = args.User.Settings.FewerNumbers
)
_, err := zhttp.Decode(r, &args)
if err != nil {
return err
}

if oldFewerNums && !args.User.Settings.FewerNumbers && args.User.Settings.FewerNumbersLockUntil.After(ztime.Now()) {
zhttp.FlashError(w, "Nice try")
return zhttp.SeeOther(w, "/user/pref")
}

if args.FewerNumbersLock != "" {
args.User.Settings.FewerNumbersLockUntil = ztime.Time{ztime.Now()}.
In(args.User.Settings.Timezone.Location).
AddPeriod(1, map[string]ztime.Period{"week": ztime.WeekMonday, "month": ztime.Month}[args.FewerNumbersLock]).
StartOf(ztime.Day).
Time
}

var (
emailChanged = goatcounter.Config(r.Context()).GoatcounterCom && oldEmail != args.User.Email
reportingChanged = goatcounter.Config(r.Context()).GoatcounterCom && oldReports != args.User.Settings.EmailReports
)

if reportingChanged {
args.User.LastReportAt = ztime.Now()
}
Expand Down
5 changes: 5 additions & 0 deletions public/backend.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,11 @@
var zone = Intl.DateTimeFormat().resolvedOptions().timeZone
$(`#timezone [value$="${zone}"]`).prop('selected', true)
})

// Lock "fewer numbers"
$('[id="user.settings.fewer_numbers"]').on('change', function(e) {
$('#lock-settings').css('display', $(this).is(':checked') ? 'block' : 'none')
}).trigger('change')
}

var page_user_dashboard = function() {
Expand Down
35 changes: 19 additions & 16 deletions public/dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -535,23 +535,26 @@
views = daily ? day.Daily : day.Hourly[i%24]

let title = ''
let future = futureFrom && x >= futureFrom - 1
if (daily)
title = `${format_date(day.Day)}, `
title = `${format_date(day.Day)}`
else
title = `${format_date(day.Day)} ${un24(start)}${un24(end)}; `
if (futureFrom && x >= futureFrom - 1)
title += T('dashboard/future')
else if (isEvent) {
title += T('dashboard/tooltip-event', {
unique: format_int(visits),
clicks: `<span class="views">${format_int(views)}`,
}) + '</span>'
}
else {
title += T('dashboard/totals/num-visits', {
'num-visits': format_int(visits),
'num-views': `<span class="views">${format_int(views)}`,
}) + '</span>'
title = `${format_date(day.Day)} ${un24(start)}${un24(end)}`
if (future)
title += '; ' + T('dashboard/future')
if (!future && !USER_SETTINGS.fewer_numbers) {
if (isEvent) {
title += '; ' + T('dashboard/tooltip-event', {
unique: format_int(visits),
clicks: `<span class="views">${format_int(views)}`,
}) + '</span>'
}
else {
title += '; ' + T('dashboard/totals/num-visits', {
'num-visits': format_int(visits),
'num-views': `<span class="views">${format_int(views)}`,
}) + '</span>'
}
}

tip.remove()
Expand Down Expand Up @@ -693,7 +696,7 @@
data: append_period({
widget: widget,
key: path,
total: row.find('>.col-count').text().replace(/[^0-9]+/g, ''),
total: row.attr('data-count'),
offset: row.find('.refs .rows>div').length,
}),
success: function(data) {
Expand Down
21 changes: 12 additions & 9 deletions settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"sort"
"strconv"
"strings"
"time"
"unicode"

"zgo.at/json"
Expand Down Expand Up @@ -72,15 +73,17 @@ type (

// UserSettings are all user preferences.
UserSettings struct {
TwentyFourHours bool `json:"twenty_four_hours"`
SundayStartsWeek bool `json:"sunday_starts_week"`
Language string `json:"language"`
DateFormat string `json:"date_format"`
NumberFormat rune `json:"number_format"`
Timezone *tz.Zone `json:"timezone"`
Widgets Widgets `json:"widgets"`
Views Views `json:"views"`
EmailReports zint.Int `json:"email_reports"`
TwentyFourHours bool `json:"twenty_four_hours"`
SundayStartsWeek bool `json:"sunday_starts_week"`
Language string `json:"language"`
DateFormat string `json:"date_format"`
NumberFormat rune `json:"number_format"`
Timezone *tz.Zone `json:"timezone"`
Widgets Widgets `json:"widgets"`
Views Views `json:"views"`
EmailReports zint.Int `json:"email_reports"`
FewerNumbers bool `json:"fewer_numbers"`
FewerNumbersLockUntil time.Time `json:"fewer_numbers_lock_until"`
}

// Widgets is a list of widgets to be printed, in order.
Expand Down
10 changes: 7 additions & 3 deletions tpl.go
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,7 @@ func HorizontalChart(ctx context.Context, stats HitStats, total int, link, pagin
}

var (
user = MustGetUser(ctx)
displayed int
b = new(strings.Builder)
)
Expand Down Expand Up @@ -480,6 +481,11 @@ func HorizontalChart(ctx context.Context, stats HitStats, total int, link, pagin
`<span class="bar-c"><span class="cutoff">%s</span> %s</span>`, perc, ename, visit)
}

ncol := ""
if !user.Settings.FewerNumbers {
ncol = tplfunc.Number(s.CountUnique, user.Settings.NumberFormat)
}

id := s.ID
if id == "" {
id = name
Expand All @@ -490,9 +496,7 @@ func HorizontalChart(ctx context.Context, stats HitStats, total int, link, pagin
<span class="col-name">%[4]s</span>
<span class="col-count">%[5]s</span>
</div>`,
class, id, perc, ref,
tplfunc.Number(s.CountUnique, MustGetUser(ctx).Settings.NumberFormat),
)
class, id, perc, ref, ncol)
}
b.WriteString(`</div>`)

Expand Down
12 changes: 7 additions & 5 deletions tpl/_dashboard_pages.gohtml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
<div class="pages-list {{if .Daily}}pages-list-daily{{end}}" data-widget="{{.ID}}">
<div class="widget-header">
<h2 class="full-width">{{t .Context "dashboard/pages/header|Pages"}}
<small>{{t .Context `dashboard/pages/num-visits|%(num-visits) out of %(total-visits) visits shown`
(map
"num-visits" (tag "span" `class="total-unique-display"` (nformat .TotalUniqueDisplay $.User))
"total-visits" (tag "span" `class="total-unique"` (nformat .TotalUnique $.User))
)}}</small>
{{if not $.User.Settings.FewerNumbers}}
<small>{{t .Context `dashboard/pages/num-visits|%(num-visits) out of %(total-visits) visits shown`
(map
"num-visits" (tag "span" `class="total-unique-display"` (nformat .TotalUniqueDisplay $.User))
"total-visits" (tag "span" `class="total-unique"` (nformat .TotalUnique $.User))
)}}</small>
{{end}}
</h2>
<a href="#" class="logged-in configure-widget" aria-label="{{t $.Context "button/cfg-dashboard|Configure"}}">⚙&#xfe0f;</a>
</div>
Expand Down
23 changes: 16 additions & 7 deletions tpl/_dashboard_pages_rows.gohtml
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
{{range $i, $h := .Pages}}
<tr id="{{$h.Path}}" data-id="{{$h.PathID}}" class="{{if eq $h.Path $.ShowRefs}}target{{end}} {{if $h.Event}}event{{end}}">
<td class="col-count">
<span title="{{nformat $h.Count $.User}} {{if $h.Event}}total clicks{{else}}pageviews{{end}}">{{nformat $h.CountUnique $.User}}</span>
</td>
<tr id="{{$h.Path}}" data-id="{{$h.PathID}}" data-count="{{$h.Count}}"
class="{{if eq $h.Path $.ShowRefs}}target{{end}} {{if $h.Event}}event{{end}}"
>
{{if not $.User.Settings.FewerNumbers}}
<td class="col-count">
<span title="{{nformat $h.Count $.User}} {{if $h.Event}}total clicks{{else}}pageviews{{end}}">{{nformat $h.CountUnique $.User}}</span>
</td>
{{end}}
<td class="col-path hide-mobile">
<a class="load-refs rlink" title="{{$h.Path}}" href="#">{{$h.Path}}</a><br>
<small class="page-title {{if not $h.Title}}no-title{{end}}">{{if $h.Title}}{{$h.Title}}{{else}}<em>({{t $.Context "no-title|no title"}})</em>{{end}}</small>
Expand All @@ -21,11 +25,16 @@
<br><small class="go"><a target="_blank" rel="noopener" href="{{$.Site.LinkDomainURL true $h.Path}}">{{t $.Context "link/goto-path|Go to %(path)" ($.Site.LinkDomainURL false $h.Path)}}</a></small>
{{end}}
</div>
<div class="chart chart-{{$.Style}}" data-max="{{$h.Max}}" data-stats="{{.Stats | json}}" data-daily="{{$.Daily}}">
<span class="chart-left"><a href="#" class="rescale" title="{{t $.Context "scale-y|Scale the Y-axis of all charts the to highest value in this chart (%(n))" $h.Max}}">↕&#xfe0e;</a></span>
<div class="chart chart-{{$.Style}}"
data-max="{{$h.Max}}" data-stats="{{.Stats | json}}"
data-daily="{{$.Daily}}"
>
{{if not $.User.Settings.FewerNumbers}}
<span class="chart-left"><a href="#" class="rescale" title="{{t $.Context "scale-y|Scale the Y-axis of all charts the to highest value in this chart (%(n))" $h.Max}}">↕&#xfe0e;</a></span>
{{end}}
<canvas height="50"></canvas>
<span class="chart-right">{{$n := sum $.Offset $i}}
{{- if (eq $i 0)}}<small class="scale" title="{{t $.Context "y-scale|Y-axis scale"}}">{{nformat $.Max $.User}}</small>
{{- if and (eq $i 0) (not $.User.Settings.FewerNumbers)}}<small class="scale" title="{{t $.Context "y-scale|Y-axis scale"}}">{{nformat $.Max $.User}}</small>
{{- else if ge $n 11}}<span class="page-n" title="{{t $.Context "page-ranking|Page ranking"}}">#{{$n}}</span>{{end -}}
</span>
</div>
Expand Down
18 changes: 11 additions & 7 deletions tpl/_dashboard_pages_text.gohtml
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
<div class="pages-list pages-list-text {{if .Daily}}pages-list-daily{{end}}" data-widget="{{.ID}}">
<div class="widget-header">
<h2 class="full-width">{{t .Context "dashboard/pages/header|Pages"}}
<small>{{t .Context `dashboard/pages/num-visits|%(num-visits) out of %(total-visits) visits shown`
(map
"num-visits" (tag "span" `class="total-unique-display"` (nformat .TotalUniqueDisplay $.User))
"total-visits" (tag "span" `class="total-unique"` (nformat .TotalUnique $.User))
)}}</small>
{{if not $.User.Settings.FewerNumbers}}
<small>{{t .Context `dashboard/pages/num-visits|%(num-visits) out of %(total-visits) visits shown`
(map
"num-visits" (tag "span" `class="total-unique-display"` (nformat .TotalUniqueDisplay $.User))
"total-visits" (tag "span" `class="total-unique"` (nformat .TotalUnique $.User))
)}}</small>
{{end}}
</h2>
<a href="#" class="logged-in configure-widget" aria-label="{{t $.Context "button/cfg-dashboard|Configure"}}">⚙&#xfe0f;</a>
</div>

<table class="count-list count-list-pages count-list-text" data-max="{{.Max}}">
<thead><tr>
<th class="col-idx"></th>
<th class="col-n">{{t .Context "dashboard/pages/visits|Visits"}}</th>
<th class="col-n" title="{{t .Context "dashboard/pages/pageviews|Pageviews"}}">{{t .Context "dashboard/pages/views|Views"}}</th>
{{if not $.User.Settings.FewerNumbers}}
<th class="col-n">{{t .Context "dashboard/pages/visits|Visits"}}</th>
<th class="col-n" title="{{t .Context "dashboard/pages/pageviews|Pageviews"}}">{{t .Context "dashboard/pages/views|Views"}}</th>
{{end}}
<th class="col-p">{{t .Context "dashboard/pages/path|Path"}}</th>
<th class="col-t">{{t .Context "dashboard/pages/title|Title"}}</th>
<th class="col-d" title="{{t .Context "dashboard/pages/stats-tooltip|Every bar represents 1/12th of the selected time range"}}">{{t .Context "dashboard/pages/stats|Stats"}}</th>
Expand Down
6 changes: 4 additions & 2 deletions tpl/_dashboard_pages_text_rows.gohtml
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
{{range $i, $h := .Pages}}
<tr id="{{$h.Path}}" data-id="{{$h.PathID}}" class="{{if eq $h.Path $.ShowRefs}}target{{end}} {{if $h.Event}}event{{end}}">
<td class="col-idx">{{sum $.Offset $i}}</td>
<td class="col-n col-count">{{nformat $h.CountUnique $.User}}</td>
<td class="col-n">{{nformat $h.Count $.User}}</td>
{{if not $.User.Settings.FewerNumbers}}
<td class="col-n col-count">{{nformat $h.CountUnique $.User}}</td>
<td class="col-n">{{nformat $h.Count $.User}}</td>
{{end}}
<td class="col-p">
<a class="load-refs rlink" href="#">{{$h.Path}}</a>

Expand Down
26 changes: 14 additions & 12 deletions tpl/_dashboard_totals.gohtml
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
<div class="totals" data-widget="{{.ID}}">
<div class="widget-header">
<h2 class="full-width">{{t .Context "dashboard/totals/header|Totals"}}
{{if .NoEvents}}
<small>{{t .Context `dashboard/totals/num-visits|%(num-visits) visits; %(num-views) pageviews; excluding events`
(map
"num-visits" (tag "span" `` (nformat (sub .TotalUnique .TotalEventsUnique) $.User))
"num-views" (tag "span" `` (nformat (sub .Total .TotalEvents) $.User))
)}}</small>
{{else}}
<small>{{t .Context `dashboard/totals/num-visits|%(num-visits) visits; %(num-views) pageviews`
(map
"num-visits" (tag "span" `` (nformat .TotalUnique $.User))
"num-views" (tag "span" `` (nformat .Total $.User))
)}}</small>
{{if not $.User.Settings.FewerNumbers}}
{{if .NoEvents}}
<small>{{t .Context `dashboard/totals/num-visits|%(num-visits) visits; %(num-views) pageviews; excluding events`
(map
"num-visits" (tag "span" `` (nformat (sub .TotalUnique .TotalEventsUnique) $.User))
"num-views" (tag "span" `` (nformat (sub .Total .TotalEvents) $.User))
)}}</small>
{{else}}
<small>{{t .Context `dashboard/totals/num-visits|%(num-visits) visits; %(num-views) pageviews`
(map
"num-visits" (tag "span" `` (nformat .TotalUnique $.User))
"num-views" (tag "span" `` (nformat .Total $.User))
)}}</small>
{{end}}
{{end}}
</h2>
<a href="#" class="logged-in configure-widget" aria-label="{{t $.Context "button/cfg-dashboard|Configure"}}">⚙&#xfe0f;</a>
Expand Down
4 changes: 3 additions & 1 deletion tpl/_dashboard_totals_row.gohtml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
<td>
<div class="chart chart-{{$.Style}}" data-max="{{.Max}}" data-stats="{{.Page.Stats | json}}" data-daily="{{.Daily}}">
{{if .Loaded}}
<span class="chart-right"><small class="scale" title="Y-axis scale">{{nformat .Max $.User}}</small></span>
{{if not $.User.Settings.FewerNumbers}}
<span class="chart-right"><small class="scale" title="Y-axis scale">{{nformat .Max $.User}}</small></span>
{{end}}
<canvas></canvas>
{{else}}
{{t $.Context "dashboard/loading|Loading…"}}
Expand Down
35 changes: 35 additions & 0 deletions tpl/user_pref.gohtml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,41 @@
<span><a href="#_" id="set-local-tz">{{.T "link/set-from-browser|Set from browser"}}</a></span>
</fieldset>

<fieldset id="section-fewer-numbers">
<legend>{{.T "header/fewer-number|Show fewer numbers"}}</legend>

<label>
<input type="checkbox" name="user.settings.fewer_numbers" id="user.settings.fewer_numbers"
{{if .User.Settings.FewerNumbers}}checked{{end}}
{{if .FewerNumbersLocked}}disabled{{end}}
>
<input type="hidden" name="user.settings.fewer_numbers" value="{{if .FewerNumbersLocked}}on{{else}}off{{end}}">
{{.T "label/fewer-numbers|Show fewer numbers"}}
</label>
<span>{{.T `help/fewer-numbers|
Don’t show numbers on the dashboard. This is intended to
still give a reasonably useful overview of what happens on
your site but prevent an “obsession” over the exact number
of visitors and stats.
`}}</span>

<div id="lock-settings">
{{if .FewerNumbersLocked}}
<br>
{{.T "help/locked-until|Locked until %(date)"
(.User.Settings.FewerNumbersLockUntil.Format .User.Settings.DateFormat)}}
{{else}}
<label for="fewer-numbers-lock">{{.T "label/lock-setting|Lock setting"}}</label>
<select id="fewer-numbers-lock" name="fewer_numbers_lock">
<option value="">{{.T "dont-lock|Don’t lock"}}</option>
<option value="week">{{(.T "nav-dash/week|week") | string|ucfirst}}</option>
<option value="month">{{(.T "nav-dash/month|month") | string|ucfirst}}</option>
<select>
<span>{{.T "help/fewer-numbers-lock|You won’t be able to disable this setting for the given time period."}}</span>
{{end}}
</div>
</fieldset>

<fieldset id="section-email-reports">
<legend>{{.T "header/email-reports|Email reports"}}</legend>
<label for="email_reports">{{.T "label/email-reports|Send email reports"}}</label>
Expand Down

0 comments on commit 0f26b42

Please sign in to comment.