@nodewrite-labs/analytics-sdk 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-MOCOVYQK.js +108 -0
- package/dist/{chunk-GVOESWHZ.js → chunk-QPHMFHRE.js} +103 -47
- package/dist/{chunk-Q4JRXZ6M.js → chunk-YAC3MRH3.js} +14 -0
- package/dist/client/index.js +3 -1
- package/dist/{event-store-BH-ZR3yD.d.ts → event-store-BkSuP4ZE.d.ts} +41 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +13 -1
- package/dist/payload/admin-filters.d.ts +24 -0
- package/dist/payload/admin-filters.js +33 -0
- package/dist/payload/admin-view.d.ts +2 -1
- package/dist/payload/admin-view.js +683 -250
- package/dist/payload/index.d.ts +65 -37
- package/dist/payload/index.js +26 -9
- package/dist/payload/nav-link.js +24 -2
- package/dist/postgres/index.js +1 -1
- package/package.json +113 -90
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// src/core/period.ts
|
|
2
|
+
var AnalyticsPeriod = {
|
|
3
|
+
LAST_24_HOURS: "24h",
|
|
4
|
+
LAST_7_DAYS: "7d",
|
|
5
|
+
LAST_30_DAYS: "30d",
|
|
6
|
+
LAST_12_MONTHS: "12m"
|
|
7
|
+
};
|
|
8
|
+
var ANALYTICS_PERIODS = Object.values(AnalyticsPeriod);
|
|
9
|
+
var DEFAULT_ANALYTICS_PERIOD = AnalyticsPeriod.LAST_7_DAYS;
|
|
10
|
+
var AnalyticsBucketUnit = {
|
|
11
|
+
HOUR: "hour",
|
|
12
|
+
DAY: "day",
|
|
13
|
+
MONTH: "month"
|
|
14
|
+
};
|
|
15
|
+
var PERIOD_BUCKETS = {
|
|
16
|
+
[AnalyticsPeriod.LAST_24_HOURS]: { unit: AnalyticsBucketUnit.HOUR, count: 24 },
|
|
17
|
+
[AnalyticsPeriod.LAST_7_DAYS]: { unit: AnalyticsBucketUnit.DAY, count: 7 },
|
|
18
|
+
[AnalyticsPeriod.LAST_30_DAYS]: { unit: AnalyticsBucketUnit.DAY, count: 30 },
|
|
19
|
+
[AnalyticsPeriod.LAST_12_MONTHS]: { unit: AnalyticsBucketUnit.MONTH, count: 12 }
|
|
20
|
+
};
|
|
21
|
+
function isAnalyticsPeriod(value) {
|
|
22
|
+
return typeof value === "string" && ANALYTICS_PERIODS.includes(value);
|
|
23
|
+
}
|
|
24
|
+
function assertTimeZone(timeZone) {
|
|
25
|
+
zonedFormatter(timeZone);
|
|
26
|
+
}
|
|
27
|
+
function analyticsPeriodRange(period, now, timeZone) {
|
|
28
|
+
const { unit, count } = PERIOD_BUCKETS[period];
|
|
29
|
+
const wall = zonedParts(now.getTime(), timeZone);
|
|
30
|
+
const starts = [];
|
|
31
|
+
for (let back = count - 1; back >= -1; back -= 1) {
|
|
32
|
+
starts.push(wallToInstant(bucketWallStart(unit, wall, back), timeZone));
|
|
33
|
+
}
|
|
34
|
+
const buckets = [];
|
|
35
|
+
for (let index = 0; index < count; index += 1) {
|
|
36
|
+
buckets.push({ start: iso(starts[index]), end: iso(starts[index + 1]) });
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
period,
|
|
40
|
+
unit,
|
|
41
|
+
from: iso(starts[0]),
|
|
42
|
+
to: now.toISOString(),
|
|
43
|
+
buckets
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function bucketWallStart(unit, wall, back) {
|
|
47
|
+
if (unit === AnalyticsBucketUnit.HOUR) {
|
|
48
|
+
return Date.UTC(wall.year, wall.month - 1, wall.day, wall.hour - back);
|
|
49
|
+
}
|
|
50
|
+
if (unit === AnalyticsBucketUnit.DAY) {
|
|
51
|
+
return Date.UTC(wall.year, wall.month - 1, wall.day - back);
|
|
52
|
+
}
|
|
53
|
+
return Date.UTC(wall.year, wall.month - 1 - back, 1);
|
|
54
|
+
}
|
|
55
|
+
function wallToInstant(wall, timeZone) {
|
|
56
|
+
const guess = wall - zoneOffsetMs(wall, timeZone);
|
|
57
|
+
return wall - zoneOffsetMs(guess, timeZone);
|
|
58
|
+
}
|
|
59
|
+
function zoneOffsetMs(instant, timeZone) {
|
|
60
|
+
const parts = zonedParts(instant, timeZone);
|
|
61
|
+
const asUtc = Date.UTC(parts.year, parts.month - 1, parts.day, parts.hour, parts.minute, parts.second);
|
|
62
|
+
return asUtc - Math.floor(instant / 1e3) * 1e3;
|
|
63
|
+
}
|
|
64
|
+
var formatters = /* @__PURE__ */ new Map();
|
|
65
|
+
function zonedFormatter(timeZone) {
|
|
66
|
+
const cached = formatters.get(timeZone);
|
|
67
|
+
if (cached) return cached;
|
|
68
|
+
const formatter = new Intl.DateTimeFormat("en-US", {
|
|
69
|
+
timeZone,
|
|
70
|
+
hourCycle: "h23",
|
|
71
|
+
year: "numeric",
|
|
72
|
+
month: "2-digit",
|
|
73
|
+
day: "2-digit",
|
|
74
|
+
hour: "2-digit",
|
|
75
|
+
minute: "2-digit",
|
|
76
|
+
second: "2-digit"
|
|
77
|
+
});
|
|
78
|
+
formatters.set(timeZone, formatter);
|
|
79
|
+
return formatter;
|
|
80
|
+
}
|
|
81
|
+
function zonedParts(instant, timeZone) {
|
|
82
|
+
const parts = {};
|
|
83
|
+
for (const part of zonedFormatter(timeZone).formatToParts(new Date(instant))) {
|
|
84
|
+
if (part.type !== "literal") parts[part.type] = Number(part.value);
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
year: parts.year ?? 0,
|
|
88
|
+
month: parts.month ?? 1,
|
|
89
|
+
day: parts.day ?? 1,
|
|
90
|
+
hour: parts.hour ?? 0,
|
|
91
|
+
minute: parts.minute ?? 0,
|
|
92
|
+
second: parts.second ?? 0
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function iso(instant) {
|
|
96
|
+
if (instant === void 0) throw new RangeError("A period bucket has no start");
|
|
97
|
+
return new Date(instant).toISOString();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export {
|
|
101
|
+
AnalyticsPeriod,
|
|
102
|
+
ANALYTICS_PERIODS,
|
|
103
|
+
DEFAULT_ANALYTICS_PERIOD,
|
|
104
|
+
AnalyticsBucketUnit,
|
|
105
|
+
isAnalyticsPeriod,
|
|
106
|
+
assertTimeZone,
|
|
107
|
+
analyticsPeriodRange
|
|
108
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
acceptDurationSeconds,
|
|
3
3
|
summarizeAnalyticsEvents
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-YAC3MRH3.js";
|
|
5
5
|
import {
|
|
6
6
|
AnalyticsEventKind
|
|
7
7
|
} from "./chunk-F7BY2JQ3.js";
|
|
@@ -17,42 +17,85 @@ function analyticsEventsAccess(read) {
|
|
|
17
17
|
};
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
// src/payload/admin/
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
20
|
+
// src/payload/admin/translations.ts
|
|
21
|
+
var ANALYTICS_TRANSLATION_NAMESPACE = "analytics";
|
|
22
|
+
var ENGLISH_ANALYTICS_LABELS = {
|
|
23
|
+
navGroup: "Statistics",
|
|
24
|
+
navLabel: "Analytics",
|
|
25
|
+
title: "Analytics",
|
|
26
|
+
period: "Period",
|
|
27
|
+
period_24h: "Last 24 hours",
|
|
28
|
+
period_7d: "Last 7 days",
|
|
29
|
+
period_30d: "Last 30 days",
|
|
30
|
+
period_12m: "Last 12 months",
|
|
31
|
+
country: "Country",
|
|
32
|
+
allCountries: "All countries",
|
|
33
|
+
views: "Views",
|
|
34
|
+
averageTime: "Average time on page",
|
|
35
|
+
clicks: "Clicks",
|
|
36
|
+
viewsOverTime: "Views over time",
|
|
37
|
+
topPages: "Top pages",
|
|
38
|
+
allPages: "All pages",
|
|
39
|
+
showAllPages: "Show all pages",
|
|
40
|
+
showTopPages: "Show top pages only",
|
|
41
|
+
page: "Page",
|
|
42
|
+
pageFilter: "Page: {{path}}",
|
|
43
|
+
clearFilter: "Clear",
|
|
44
|
+
countries: "Countries",
|
|
45
|
+
cities: "Cities",
|
|
46
|
+
city: "City",
|
|
47
|
+
event: "Event",
|
|
48
|
+
count: "Count",
|
|
49
|
+
sessions: "Sessions",
|
|
50
|
+
session: "Session",
|
|
51
|
+
started: "Started",
|
|
52
|
+
pages: "Pages",
|
|
53
|
+
sessionEvents: "Session events",
|
|
54
|
+
allSessions: "All sessions",
|
|
55
|
+
time: "Time",
|
|
56
|
+
kind: "Kind",
|
|
57
|
+
kindView: "View",
|
|
58
|
+
kindClick: "Click",
|
|
59
|
+
empty: "Nothing in this period."
|
|
60
|
+
};
|
|
61
|
+
function withAnalyticsTranslations(i18n, translations = {}) {
|
|
62
|
+
const existing = i18n?.translations ?? {};
|
|
63
|
+
const languages = /* @__PURE__ */ new Set([
|
|
64
|
+
"en",
|
|
65
|
+
...Object.keys(i18n?.supportedLanguages ?? {}),
|
|
66
|
+
...Object.keys(translations)
|
|
67
|
+
]);
|
|
68
|
+
const merged = { ...existing };
|
|
69
|
+
for (const language of languages) {
|
|
70
|
+
const current = existing[language] ?? {};
|
|
71
|
+
const host = translations[language] ?? {};
|
|
72
|
+
merged[language] = {
|
|
73
|
+
...current,
|
|
74
|
+
[ANALYTICS_TRANSLATION_NAMESPACE]: {
|
|
75
|
+
...ENGLISH_ANALYTICS_LABELS,
|
|
76
|
+
...host,
|
|
77
|
+
events: { ...host.events }
|
|
78
|
+
}
|
|
79
|
+
};
|
|
39
80
|
}
|
|
40
|
-
return
|
|
81
|
+
return { ...i18n, translations: merged };
|
|
41
82
|
}
|
|
42
|
-
function
|
|
43
|
-
|
|
44
|
-
const trimmed = value.trim();
|
|
45
|
-
return trimmed.length === 0 ? null : trimmed;
|
|
83
|
+
function analyticsLabel(t, key, vars) {
|
|
84
|
+
return t(`${ANALYTICS_TRANSLATION_NAMESPACE}:${key}`, vars);
|
|
46
85
|
}
|
|
47
|
-
function
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
if (left.id < right.id) return -1;
|
|
52
|
-
if (left.id > right.id) return 1;
|
|
53
|
-
return 0;
|
|
54
|
-
});
|
|
86
|
+
function analyticsEventLabel(translations, eventName) {
|
|
87
|
+
const namespace = property(translations, ANALYTICS_TRANSLATION_NAMESPACE);
|
|
88
|
+
const label = property(property(namespace, "events"), eventName);
|
|
89
|
+
return typeof label === "string" && label.length > 0 ? label : eventName;
|
|
55
90
|
}
|
|
91
|
+
function property(value, key) {
|
|
92
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
93
|
+
return value[key];
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// src/payload/admin/component-paths.ts
|
|
97
|
+
var ANALYTICS_FILTERS_PATH = "@nodewrite-labs/analytics-sdk/payload/admin-filters#AnalyticsFilters";
|
|
98
|
+
var ANALYTICS_FILTERS_DEPENDENCY = "nodewriteAnalyticsFilters";
|
|
56
99
|
|
|
57
100
|
// src/payload/collection.ts
|
|
58
101
|
var ANALYTICS_EVENTS_SLUG = "analytics-events";
|
|
@@ -242,29 +285,42 @@ function timeText(value) {
|
|
|
242
285
|
|
|
243
286
|
// src/payload/stored-modules.ts
|
|
244
287
|
var ANALYTICS_CUSTOM_KEY = "analytics";
|
|
245
|
-
|
|
288
|
+
var DEFAULT_ANALYTICS_TIME_ZONE = "UTC";
|
|
289
|
+
var MODULES_OFF = { country: false, city: false, sessions: false, clicks: false };
|
|
290
|
+
function analyticsAdminSettingsFromConfig(config) {
|
|
246
291
|
const stored = config.custom?.[ANALYTICS_CUSTOM_KEY];
|
|
247
|
-
if (!
|
|
248
|
-
return {
|
|
292
|
+
if (!isRecord2(stored) || !isModules(stored.modules)) {
|
|
293
|
+
return { modules: MODULES_OFF, timeZone: DEFAULT_ANALYTICS_TIME_ZONE, formatLocales: {} };
|
|
249
294
|
}
|
|
250
|
-
return
|
|
295
|
+
return {
|
|
296
|
+
modules: stored.modules,
|
|
297
|
+
timeZone: typeof stored.timeZone === "string" ? stored.timeZone : DEFAULT_ANALYTICS_TIME_ZONE,
|
|
298
|
+
formatLocales: isStringRecord(stored.formatLocales) ? stored.formatLocales : {}
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
function isModules(value) {
|
|
302
|
+
if (!isRecord2(value)) return false;
|
|
303
|
+
return typeof value.country === "boolean" && typeof value.city === "boolean" && typeof value.sessions === "boolean" && typeof value.clicks === "boolean";
|
|
251
304
|
}
|
|
252
|
-
function
|
|
253
|
-
|
|
254
|
-
const modules = value.modules;
|
|
255
|
-
if (typeof modules !== "object" || modules === null) return false;
|
|
256
|
-
return hasBoolean(modules, "country") && hasBoolean(modules, "city") && hasBoolean(modules, "sessions") && hasBoolean(modules, "clicks");
|
|
305
|
+
function isStringRecord(value) {
|
|
306
|
+
return isRecord2(value) && Object.values(value).every((entry) => typeof entry === "string");
|
|
257
307
|
}
|
|
258
|
-
function
|
|
259
|
-
|
|
260
|
-
return typeof record[key] === "boolean";
|
|
308
|
+
function isRecord2(value) {
|
|
309
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
261
310
|
}
|
|
262
311
|
|
|
263
312
|
export {
|
|
264
313
|
analyticsEventsAccess,
|
|
265
|
-
|
|
314
|
+
ENGLISH_ANALYTICS_LABELS,
|
|
315
|
+
withAnalyticsTranslations,
|
|
316
|
+
analyticsLabel,
|
|
317
|
+
analyticsEventLabel,
|
|
318
|
+
ANALYTICS_FILTERS_PATH,
|
|
319
|
+
ANALYTICS_FILTERS_DEPENDENCY,
|
|
320
|
+
ANALYTICS_EVENTS_SLUG,
|
|
266
321
|
analyticsEventsCollection,
|
|
267
322
|
PayloadAnalyticsEventStore,
|
|
268
323
|
ANALYTICS_CUSTOM_KEY,
|
|
269
|
-
|
|
324
|
+
DEFAULT_ANALYTICS_TIME_ZONE,
|
|
325
|
+
analyticsAdminSettingsFromConfig
|
|
270
326
|
};
|
|
@@ -20,6 +20,9 @@ function summarizeAnalyticsEvents(rows, query, modules) {
|
|
|
20
20
|
averageDurationSeconds: meanDuration(views),
|
|
21
21
|
byPath: groupByPath(views)
|
|
22
22
|
};
|
|
23
|
+
if (query.buckets) {
|
|
24
|
+
summary.viewsOverTime = countViewsByBucket(views, query.buckets);
|
|
25
|
+
}
|
|
23
26
|
if (modules.country) {
|
|
24
27
|
summary.byCountry = groupByCountry(views);
|
|
25
28
|
}
|
|
@@ -61,6 +64,17 @@ function meanDuration(views) {
|
|
|
61
64
|
if (count === 0) return 0;
|
|
62
65
|
return total / count;
|
|
63
66
|
}
|
|
67
|
+
function countViewsByBucket(views, buckets) {
|
|
68
|
+
const counts = buckets.map(() => 0);
|
|
69
|
+
const ends = buckets.map((bucket) => Date.parse(bucket.end));
|
|
70
|
+
const starts = buckets.map((bucket) => Date.parse(bucket.start));
|
|
71
|
+
for (const view of views) {
|
|
72
|
+
const at = Date.parse(view.occurredAt);
|
|
73
|
+
const index = starts.findIndex((start, position) => at >= start && at < (ends[position] ?? start));
|
|
74
|
+
if (index >= 0) counts[index] = (counts[index] ?? 0) + 1;
|
|
75
|
+
}
|
|
76
|
+
return buckets.map((bucket, index) => ({ start: bucket.start, views: counts[index] ?? 0 }));
|
|
77
|
+
}
|
|
64
78
|
function groupByPath(views) {
|
|
65
79
|
const groups = /* @__PURE__ */ new Map();
|
|
66
80
|
for (const view of views) {
|
package/dist/client/index.js
CHANGED
|
@@ -199,7 +199,9 @@ async function postJson(url, body) {
|
|
|
199
199
|
return fetch(url, {
|
|
200
200
|
method: "POST",
|
|
201
201
|
headers: { "Content-Type": "application/json" },
|
|
202
|
-
body: JSON.stringify(body)
|
|
202
|
+
body: JSON.stringify(body),
|
|
203
|
+
// A tel: or mailto: click can hand the page to another app before the request finishes.
|
|
204
|
+
keepalive: true
|
|
203
205
|
});
|
|
204
206
|
}
|
|
205
207
|
async function readViewId(response) {
|
|
@@ -21,16 +21,55 @@ interface StoredAnalyticsEvent extends NewAnalyticsEvent {
|
|
|
21
21
|
occurredAt: string;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
declare const AnalyticsPeriod: {
|
|
25
|
+
readonly LAST_24_HOURS: "24h";
|
|
26
|
+
readonly LAST_7_DAYS: "7d";
|
|
27
|
+
readonly LAST_30_DAYS: "30d";
|
|
28
|
+
readonly LAST_12_MONTHS: "12m";
|
|
29
|
+
};
|
|
30
|
+
type AnalyticsPeriod = (typeof AnalyticsPeriod)[keyof typeof AnalyticsPeriod];
|
|
31
|
+
declare const ANALYTICS_PERIODS: readonly AnalyticsPeriod[];
|
|
32
|
+
declare const DEFAULT_ANALYTICS_PERIOD: AnalyticsPeriod;
|
|
33
|
+
declare const AnalyticsBucketUnit: {
|
|
34
|
+
readonly HOUR: "hour";
|
|
35
|
+
readonly DAY: "day";
|
|
36
|
+
readonly MONTH: "month";
|
|
37
|
+
};
|
|
38
|
+
type AnalyticsBucketUnit = (typeof AnalyticsBucketUnit)[keyof typeof AnalyticsBucketUnit];
|
|
39
|
+
/** One step of the chart. `start` is inclusive and `end` exclusive, both ISO instants. */
|
|
40
|
+
interface AnalyticsBucket {
|
|
41
|
+
start: string;
|
|
42
|
+
end: string;
|
|
43
|
+
}
|
|
44
|
+
interface AnalyticsPeriodRange {
|
|
45
|
+
period: AnalyticsPeriod;
|
|
46
|
+
unit: AnalyticsBucketUnit;
|
|
47
|
+
from: string;
|
|
48
|
+
to: string;
|
|
49
|
+
buckets: AnalyticsBucket[];
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* The period that ends now: the current hour, day or month plus the ones before it, counted on
|
|
53
|
+
* the wall clock of `timeZone`, so a day starts at that zone's midnight.
|
|
54
|
+
*/
|
|
55
|
+
declare function analyticsPeriodRange(period: AnalyticsPeriod, now: Date, timeZone: string): AnalyticsPeriodRange;
|
|
56
|
+
|
|
24
57
|
interface AnalyticsSummaryQuery {
|
|
25
58
|
from: string;
|
|
26
59
|
to: string;
|
|
27
60
|
country: string | null;
|
|
28
61
|
path: string | null;
|
|
29
62
|
sessionId: string | null;
|
|
63
|
+
/** When set, the summary counts views per bucket in `viewsOverTime`. */
|
|
64
|
+
buckets?: readonly AnalyticsBucket[];
|
|
30
65
|
}
|
|
31
66
|
interface AnalyticsSummary {
|
|
32
67
|
totalViews: number;
|
|
33
68
|
averageDurationSeconds: number;
|
|
69
|
+
viewsOverTime?: {
|
|
70
|
+
start: string;
|
|
71
|
+
views: number;
|
|
72
|
+
}[];
|
|
34
73
|
byPath: {
|
|
35
74
|
path: string;
|
|
36
75
|
views: number;
|
|
@@ -68,5 +107,5 @@ interface AnalyticsEventStore {
|
|
|
68
107
|
summarizeAnalytics(query: AnalyticsSummaryQuery, modules: AnalyticsModules): Promise<AnalyticsSummary>;
|
|
69
108
|
}
|
|
70
109
|
|
|
71
|
-
export {
|
|
72
|
-
export type { AnalyticsSummaryQuery as A, NewAnalyticsEvent as N, StoredAnalyticsEvent as S, AnalyticsSummary as a, AnalyticsEventStore as b };
|
|
110
|
+
export { DEFAULT_ANALYTICS_PERIOD as D, ANALYTICS_PERIODS as c, AnalyticsBucketUnit as e, AnalyticsEventKind as f, AnalyticsPeriod as g, analyticsPeriodRange as i };
|
|
111
|
+
export type { AnalyticsSummaryQuery as A, NewAnalyticsEvent as N, StoredAnalyticsEvent as S, AnalyticsSummary as a, AnalyticsEventStore as b, AnalyticsBucket as d, AnalyticsPeriodRange as h };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { S as StoredAnalyticsEvent, A as AnalyticsSummaryQuery, a as AnalyticsSummary, b as AnalyticsEventStore, N as NewAnalyticsEvent } from './event-store-
|
|
2
|
-
export { c as AnalyticsEventKind } from './event-store-
|
|
1
|
+
import { S as StoredAnalyticsEvent, A as AnalyticsSummaryQuery, a as AnalyticsSummary, b as AnalyticsEventStore, N as NewAnalyticsEvent } from './event-store-BkSuP4ZE.js';
|
|
2
|
+
export { c as ANALYTICS_PERIODS, d as AnalyticsBucket, e as AnalyticsBucketUnit, f as AnalyticsEventKind, g as AnalyticsPeriod, h as AnalyticsPeriodRange, D as DEFAULT_ANALYTICS_PERIOD, i as analyticsPeriodRange } from './event-store-BkSuP4ZE.js';
|
|
3
3
|
import { a as AnalyticsModules } from './options-Dpx2vs4R.js';
|
|
4
4
|
export { A as AnalyticsClientConfig, b as AnalyticsServerOptions, R as ReadGeoFromHeaders, c as RequestGeo } from './options-Dpx2vs4R.js';
|
|
5
5
|
export { A as AnalyticsEventBody } from './event-body-fpV2mYpY.js';
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ANALYTICS_PERIODS,
|
|
3
|
+
AnalyticsBucketUnit,
|
|
4
|
+
AnalyticsPeriod,
|
|
5
|
+
DEFAULT_ANALYTICS_PERIOD,
|
|
6
|
+
analyticsPeriodRange
|
|
7
|
+
} from "./chunk-MOCOVYQK.js";
|
|
1
8
|
import {
|
|
2
9
|
acceptDurationSeconds,
|
|
3
10
|
summarizeAnalyticsEvents
|
|
4
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-YAC3MRH3.js";
|
|
5
12
|
import {
|
|
6
13
|
AnalyticsEventKind
|
|
7
14
|
} from "./chunk-F7BY2JQ3.js";
|
|
@@ -42,8 +49,13 @@ var MemoryAnalyticsEventStore = class {
|
|
|
42
49
|
}
|
|
43
50
|
};
|
|
44
51
|
export {
|
|
52
|
+
ANALYTICS_PERIODS,
|
|
53
|
+
AnalyticsBucketUnit,
|
|
45
54
|
AnalyticsEventKind,
|
|
55
|
+
AnalyticsPeriod,
|
|
56
|
+
DEFAULT_ANALYTICS_PERIOD,
|
|
46
57
|
MemoryAnalyticsEventStore,
|
|
47
58
|
acceptDurationSeconds,
|
|
59
|
+
analyticsPeriodRange,
|
|
48
60
|
summarizeAnalyticsEvents
|
|
49
61
|
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
/** A type alias, not an interface, so it fits Payload's index-signature `Option`. */
|
|
4
|
+
type AnalyticsFilterOption = {
|
|
5
|
+
value: string;
|
|
6
|
+
label: string;
|
|
7
|
+
};
|
|
8
|
+
interface AnalyticsFilter {
|
|
9
|
+
/** The id ties the visible label to its dropdown. */
|
|
10
|
+
id: string;
|
|
11
|
+
label: string;
|
|
12
|
+
options: AnalyticsFilterOption[];
|
|
13
|
+
value: string;
|
|
14
|
+
/** The report URL for each option's value, built on the server. */
|
|
15
|
+
hrefs: Record<string, string>;
|
|
16
|
+
}
|
|
17
|
+
interface AnalyticsFiltersProps {
|
|
18
|
+
filters: AnalyticsFilter[];
|
|
19
|
+
}
|
|
20
|
+
/** Payload's own dropdowns. Choosing an option loads that report URL. */
|
|
21
|
+
declare function AnalyticsFilters({ filters }: AnalyticsFiltersProps): react_jsx_runtime.JSX.Element;
|
|
22
|
+
|
|
23
|
+
export { AnalyticsFilters };
|
|
24
|
+
export type { AnalyticsFilter, AnalyticsFilterOption, AnalyticsFiltersProps };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/payload/admin/filters.tsx
|
|
4
|
+
import { ReactSelect } from "@payloadcms/ui";
|
|
5
|
+
import { useRouter } from "next/navigation.js";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
function AnalyticsFilters({ filters }) {
|
|
8
|
+
const router = useRouter();
|
|
9
|
+
return /* @__PURE__ */ jsx("div", { className: "nwa-filters", children: filters.map((filter) => /* @__PURE__ */ jsxs("div", { className: "nwa-filter", children: [
|
|
10
|
+
/* @__PURE__ */ jsx("label", { className: "nwa-filter__label", htmlFor: filter.id, children: filter.label }),
|
|
11
|
+
/* @__PURE__ */ jsx(
|
|
12
|
+
ReactSelect,
|
|
13
|
+
{
|
|
14
|
+
inputId: filter.id,
|
|
15
|
+
isClearable: false,
|
|
16
|
+
isSearchable: filter.options.length > 8,
|
|
17
|
+
options: filter.options,
|
|
18
|
+
value: filter.options.find((option) => option.value === filter.value),
|
|
19
|
+
onChange: (selected) => {
|
|
20
|
+
const href = filter.hrefs[optionValue(selected)];
|
|
21
|
+
if (href) router.push(href);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
)
|
|
25
|
+
] }, filter.id)) });
|
|
26
|
+
}
|
|
27
|
+
function optionValue(selected) {
|
|
28
|
+
const option = Array.isArray(selected) ? selected[0] : selected;
|
|
29
|
+
return typeof option?.value === "string" ? option.value : "";
|
|
30
|
+
}
|
|
31
|
+
export {
|
|
32
|
+
AnalyticsFilters
|
|
33
|
+
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { AdminViewServerProps } from 'payload';
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
/** The analytics screen inside Payload's own admin frame, sidebar included. */
|
|
5
|
+
declare function AnalyticsAdminView(props: AdminViewServerProps): Promise<react_jsx_runtime.JSX.Element>;
|
|
5
6
|
|
|
6
7
|
export { AnalyticsAdminView };
|