Extended analytics data collection.

This commit is contained in:
2026-08-20 19:40:05 +00:00
parent b4e8fad090
commit f0e6162f02
7 changed files with 507 additions and 64 deletions
+67
View File
@@ -52,3 +52,70 @@ export function formatRecentVisits(visits, pageTree, limit = 50) {
.filter((v) => v.steps.length)
.slice(0, limit)
}
/**
* Count distinct values of a visit field, sorted most-common first.
* Returns an array of [value, count] pairs.
*/
export function countByField(visits, field) {
const counts = {}
for (const v of visits || []) {
const value = v[field]
if (!value) continue
counts[value] = (counts[value] || 0) + 1
}
return Object.entries(counts).sort((a, b) => b[1] - a[1])
}
/**
* Count UTM parameter occurrences across visits. Each distinct
* ``parameter: value`` pair is counted separately. Returns [pair, count].
*/
export function countUtmTags(visits) {
const counts = {}
for (const v of visits || []) {
for (const [key, value] of Object.entries(v.utm || {})) {
const label = `${key}: ${value}`
counts[label] = (counts[label] || 0) + 1
}
}
return Object.entries(counts).sort((a, b) => b[1] - a[1])
}
/** Format a list of [value, count] pairs for inline display. */
export function formatCounts(entries) {
return entries.map(([value, count]) => `${value} (${count})`).join(', ')
}
/**
* Format raw visit records as rows for a technical table. Returns objects
* with display strings; missing values become "—". ``trail`` joins page
* titles (when known) with " -> ".
*/
export function formatVisitRows(visits, pageTree) {
const titles = buildTitleMap(pageTree)
return [...(visits || [])].reverse().map((v) => {
const trail = [v.entry, ...(v.trail || [])]
.filter((p) => p?.startsWith('/'))
.map((p) => ({
path: p,
slug: slugOf(p),
title: titles.get(p) || '',
}))
const utm = Object.entries(v.utm || {})
.map(([k, value]) => `${k}=${value}`)
.join(', ')
const dash = (s) => (s || '—')
return {
when: new Date(v.start).toLocaleString(),
trail,
referer: dash(v.referer),
ip: dash(v.ip),
host: dash(v.host),
lang: dash(v.lang),
country: dash(v.country),
ua: dash(v.ua),
utm: utm || '—',
}
})
}