@liiift-studio/sanity-visitor-insights 0.6.2 → 0.8.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/README.md +2 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +72 -9
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +72 -9
- package/dist/index.mjs.map +1 -1
- package/dist/{ranges-DX6B_xvr.d.mts → ranges-B1YwjGGt.d.mts} +42 -5
- package/dist/{ranges-DX6B_xvr.d.ts → ranges-B1YwjGGt.d.ts} +42 -5
- package/dist/server.d.mts +6 -11
- package/dist/server.d.ts +6 -11
- package/dist/server.js +100 -25
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +100 -25
- package/dist/server.mjs.map +1 -1
- package/dist/testing.d.mts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/{vercel-B6d1Ng48.d.mts → vercel-BnuGVKWS.d.mts} +14 -0
- package/dist/{vercel-B6d1Ng48.d.ts → vercel-BnuGVKWS.d.ts} +14 -0
- package/package.json +1 -1
- package/src/core/siteConfig.ts +10 -0
- package/src/reportData.ts +33 -4
- package/src/server/auth.ts +38 -4
- package/src/server/createHandler.ts +1 -1
- package/src/server/ga4.ts +22 -0
- package/src/server/reports/acquisition.ts +15 -3
- package/src/server/reports/journey.ts +25 -13
- package/src/server/reports/measurementHealth.ts +65 -2
- package/src/server/reports/reports.test.ts +198 -2
- package/src/server/reports/typefaceInterest.ts +19 -3
- package/src/server.ts +1 -1
- package/src/studio/Figure.tsx +84 -0
- package/src/studio/panels.test.tsx +57 -5
- package/src/studio/panels.tsx +30 -7
package/README.md
CHANGED
|
@@ -169,6 +169,8 @@ export default createVisitorInsightsHandler({
|
|
|
169
169
|
tester_engaged: null,
|
|
170
170
|
},
|
|
171
171
|
// Only needed where the Studio is on a different origin.
|
|
172
|
+
// Enforced server-side, unlike the plugin option of the same name. Set both, to the same list.
|
|
173
|
+
roles: ['administrator'],
|
|
172
174
|
allowedStudioOrigins: ['https://mckl.sanity.studio'],
|
|
173
175
|
},
|
|
174
176
|
})
|
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as sanity from 'sanity';
|
|
2
2
|
import React from 'react';
|
|
3
|
-
import { R as ReportEnvelope, a as ReportName, b as RangeKey, M as MetricValue, A as AcquisitionData, D as DiagnosticReport, J as JourneyData, c as MeasurementHealthData, T as TypefaceInterestData } from './ranges-
|
|
4
|
-
export { C as Coverage, d as DateRange, E as EventCutover, P as PREEXISTING, e as REPORT_NAMES, f as ReportError, S as SiteAnalyticsConfig, g as SourceName, h as SourceStatus, U as UnavailableReason, i as coverageForRange, j as isReportName, o as ok, p as partial, k as previousRange, r as resolveRange, u as unavailable, v as validateSiteConfig, l as valueOrNull } from './ranges-
|
|
3
|
+
import { R as ReportEnvelope, a as ReportName, b as RangeKey, M as MetricValue, A as AcquisitionData, D as DiagnosticReport, J as JourneyData, c as MeasurementHealthData, T as TypefaceInterestData } from './ranges-B1YwjGGt.mjs';
|
|
4
|
+
export { C as Coverage, d as DateRange, E as EventCutover, P as PREEXISTING, e as REPORT_NAMES, f as ReportError, S as SiteAnalyticsConfig, g as SourceName, h as SourceStatus, U as UnavailableReason, i as coverageForRange, j as isReportName, o as ok, p as partial, k as previousRange, r as resolveRange, u as unavailable, v as validateSiteConfig, l as valueOrNull } from './ranges-B1YwjGGt.mjs';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* The Visitor Insights Studio tool.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as sanity from 'sanity';
|
|
2
2
|
import React from 'react';
|
|
3
|
-
import { R as ReportEnvelope, a as ReportName, b as RangeKey, M as MetricValue, A as AcquisitionData, D as DiagnosticReport, J as JourneyData, c as MeasurementHealthData, T as TypefaceInterestData } from './ranges-
|
|
4
|
-
export { C as Coverage, d as DateRange, E as EventCutover, P as PREEXISTING, e as REPORT_NAMES, f as ReportError, S as SiteAnalyticsConfig, g as SourceName, h as SourceStatus, U as UnavailableReason, i as coverageForRange, j as isReportName, o as ok, p as partial, k as previousRange, r as resolveRange, u as unavailable, v as validateSiteConfig, l as valueOrNull } from './ranges-
|
|
3
|
+
import { R as ReportEnvelope, a as ReportName, b as RangeKey, M as MetricValue, A as AcquisitionData, D as DiagnosticReport, J as JourneyData, c as MeasurementHealthData, T as TypefaceInterestData } from './ranges-B1YwjGGt.js';
|
|
4
|
+
export { C as Coverage, d as DateRange, E as EventCutover, P as PREEXISTING, e as REPORT_NAMES, f as ReportError, S as SiteAnalyticsConfig, g as SourceName, h as SourceStatus, U as UnavailableReason, i as coverageForRange, j as isReportName, o as ok, p as partial, k as previousRange, r as resolveRange, u as unavailable, v as validateSiteConfig, l as valueOrNull } from './ranges-B1YwjGGt.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* The Visitor Insights Studio tool.
|
package/dist/index.js
CHANGED
|
@@ -171,6 +171,67 @@ function NoticeList({ notices }) {
|
|
|
171
171
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_sanity_ui_compat.Text, { size: 1, children: notice })
|
|
172
172
|
] }) }) }, notice)) });
|
|
173
173
|
}
|
|
174
|
+
function TrendChart({ points, label = "Daily pageviews, GA4 against Vercel" }) {
|
|
175
|
+
if (points.length < 3) return null;
|
|
176
|
+
const W = 720;
|
|
177
|
+
const H = 132;
|
|
178
|
+
const PAD = 4;
|
|
179
|
+
const values = points.flatMap((p) => [p.ga4, p.vercel]).filter((v) => typeof v === "number");
|
|
180
|
+
if (values.length === 0) return null;
|
|
181
|
+
const max = Math.max(...values, 1);
|
|
182
|
+
const x = (i) => PAD + i / Math.max(1, points.length - 1) * (W - PAD * 2);
|
|
183
|
+
const y = (v) => H - PAD - v / max * (H - PAD * 2);
|
|
184
|
+
const path = (pick) => {
|
|
185
|
+
let d = "";
|
|
186
|
+
let penDown = false;
|
|
187
|
+
points.forEach((p, i) => {
|
|
188
|
+
const v = pick(p);
|
|
189
|
+
if (typeof v !== "number") {
|
|
190
|
+
penDown = false;
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
d += `${penDown ? "L" : "M"}${x(i).toFixed(1)} ${y(v).toFixed(1)} `;
|
|
194
|
+
penDown = true;
|
|
195
|
+
});
|
|
196
|
+
return d.trim();
|
|
197
|
+
};
|
|
198
|
+
const vercelPath = path((p) => p.vercel);
|
|
199
|
+
const ga4Path = path((p) => p.ga4);
|
|
200
|
+
const first = points[0]?.date ?? "";
|
|
201
|
+
const last = points[points.length - 1]?.date ?? "";
|
|
202
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_sanity_ui_compat.Stack, { space: 2, children: [
|
|
203
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_sanity_ui_compat.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
204
|
+
"svg",
|
|
205
|
+
{
|
|
206
|
+
viewBox: `0 0 ${W} ${H}`,
|
|
207
|
+
width: "100%",
|
|
208
|
+
height: H,
|
|
209
|
+
role: "img",
|
|
210
|
+
"aria-label": `${label}, ${first} to ${last}. Peak ${Math.round(max)} pageviews in a day.`,
|
|
211
|
+
preserveAspectRatio: "none",
|
|
212
|
+
style: { display: "block", overflow: "visible" },
|
|
213
|
+
children: [
|
|
214
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: vercelPath, fill: "none", stroke: "currentColor", strokeOpacity: "0.85", strokeWidth: "2", vectorEffect: "non-scaling-stroke" }),
|
|
215
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: ga4Path, fill: "none", stroke: "currentColor", strokeOpacity: "0.85", strokeWidth: "2", strokeDasharray: "5 3", vectorEffect: "non-scaling-stroke" })
|
|
216
|
+
]
|
|
217
|
+
}
|
|
218
|
+
) }),
|
|
219
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_sanity_ui_compat.Flex, { gap: 3, align: "center", wrap: "wrap", children: [
|
|
220
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_sanity_ui_compat.Text, { size: 0, muted: true, children: "\u2501\u2501 Vercel" }),
|
|
221
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_sanity_ui_compat.Text, { size: 0, muted: true, children: "\u2504\u2504 GA4" }),
|
|
222
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_sanity_ui_compat.Text, { size: 0, muted: true, children: [
|
|
223
|
+
first,
|
|
224
|
+
" to ",
|
|
225
|
+
last
|
|
226
|
+
] }),
|
|
227
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_sanity_ui_compat.Text, { size: 0, muted: true, children: [
|
|
228
|
+
"peak ",
|
|
229
|
+
formatCount(max),
|
|
230
|
+
"/day"
|
|
231
|
+
] })
|
|
232
|
+
] })
|
|
233
|
+
] });
|
|
234
|
+
}
|
|
174
235
|
|
|
175
236
|
// src/studio/VisitorInsightsTool.tsx
|
|
176
237
|
var import_sanity_ui_compat4 = require("@liiift-studio/sanity-ui-compat");
|
|
@@ -195,12 +256,14 @@ function MeasurementHealthPanel({ data }) {
|
|
|
195
256
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ComparisonBar, { label: "GA4 pageviews", metric: data.ga4Pageviews, max: pageviewMax, tone: "default" })
|
|
196
257
|
] }),
|
|
197
258
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Card, { padding: 3, radius: 2, tone: "transparent", border: true, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_sanity_ui_compat2.Stack, { space: 2, children: [
|
|
198
|
-
data.shortfallRatio !== null && /* @__PURE__ */ (0, import_jsx_runtime2.
|
|
199
|
-
"GA4 shortfall: ",
|
|
200
|
-
formatPercent(Math.abs(data.shortfallRatio), 1)
|
|
201
|
-
] }),
|
|
259
|
+
data.shortfallRatio !== null && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Text, { size: 1, weight: "semibold", children: data.shortfallRatio >= 0 ? `GA4 saw ${formatPercent(data.shortfallRatio, 1)} fewer pageviews than Vercel` : `GA4 saw ${formatPercent(-data.shortfallRatio, 1)} more pageviews than Vercel` }),
|
|
202
260
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Text, { size: 1, muted: true, children: data.interpretation })
|
|
203
261
|
] }) }),
|
|
262
|
+
data.daily.length >= 3 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_sanity_ui_compat2.Stack, { space: 3, children: [
|
|
263
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Heading, { size: 1, children: "Day by day" }),
|
|
264
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Text, { size: 1, muted: true, children: "A gap that has always been there is consent and blocking. A gap that opens on one day is an incident." }),
|
|
265
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(TrendChart, { points: data.daily })
|
|
266
|
+
] }),
|
|
204
267
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_sanity_ui_compat2.Stack, { space: 3, children: [
|
|
205
268
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Heading, { size: 1, children: "Context" }),
|
|
206
269
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Text, { size: 1, muted: true, children: "Different units to the figures above, and to each other. Shown for scale, never differenced." }),
|
|
@@ -268,16 +331,16 @@ function JourneyPanel({ data }) {
|
|
|
268
331
|
" of the previous measurable step"
|
|
269
332
|
] })
|
|
270
333
|
] }, step.key)) }),
|
|
271
|
-
data.
|
|
272
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Heading, { size: 1, children: "Where sessions
|
|
334
|
+
data.topLandingPages.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_sanity_ui_compat2.Stack, { space: 3, children: [
|
|
335
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Heading, { size: 1, children: "Where sessions began" }),
|
|
273
336
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Card, { radius: 2, tone: "transparent", border: true, style: tableWrap, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("table", { style: table, children: [
|
|
274
337
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tr", { children: [
|
|
275
338
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { scope: "col", style: cell, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Label, { size: 1, muted: true, children: "Page" }) }),
|
|
276
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { scope: "col", style: numericCell, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Label, { size: 1, muted: true, children: "
|
|
339
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { scope: "col", style: numericCell, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Label, { size: 1, muted: true, children: "Sessions" }) })
|
|
277
340
|
] }) }),
|
|
278
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tbody", { children: data.
|
|
341
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tbody", { children: data.topLandingPages.map((page) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tr", { children: [
|
|
279
342
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { scope: "row", style: cell, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Text, { size: 1, children: page.path }) }),
|
|
280
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: numericCell, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Text, { size: 1, children: formatCount(page.
|
|
343
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: numericCell, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_sanity_ui_compat2.Text, { size: 1, children: formatCount(page.sessions) }) })
|
|
281
344
|
] }, page.path)) })
|
|
282
345
|
] }) })
|
|
283
346
|
] })
|