Extended analytics data collection.
This commit is contained in:
@@ -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 || '—',
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user