@liiift-studio/sanity-visitor-insights 0.32.0 → 0.34.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/index.d.mts +1 -25
- package/dist/index.d.ts +1 -25
- package/dist/index.js +13 -206
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +13 -205
- package/dist/index.mjs.map +1 -1
- package/dist/server.d.mts +2 -2
- package/dist/server.d.ts +2 -2
- package/dist/server.js +49 -28
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +49 -28
- package/dist/server.mjs.map +1 -1
- package/dist/testing.d.mts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/{vercel-CU5PgGrJ.d.mts → vercel-XCTmoX7Z.d.mts} +7 -0
- package/dist/{vercel-CU5PgGrJ.d.ts → vercel-XCTmoX7Z.d.ts} +7 -0
- package/package.json +1 -1
- package/src/core/capture.ts +41 -12
- package/src/index.ts +1 -1
- package/src/server/orders.ts +22 -13
- package/src/server/reports/measurementHealth.ts +59 -12
- package/src/server/reports/reports.test.ts +90 -0
- package/src/server/vercel.ts +35 -4
- package/src/studio/Figure.tsx +0 -228
- package/src/studio/VisitorInsightsTool.tsx +30 -4
- package/src/studio/panels.test.tsx +71 -124
package/dist/index.d.mts
CHANGED
|
@@ -341,30 +341,6 @@ interface NoticeListProps {
|
|
|
341
341
|
* Rendered in the panel rather than a README: a caveat nobody sees does not prevent a wrong read.
|
|
342
342
|
*/
|
|
343
343
|
declare function NoticeList({ notices }: NoticeListProps): React.ReactElement | null;
|
|
344
|
-
/** Props for TrendChart. */
|
|
345
|
-
interface TrendChartProps {
|
|
346
|
-
/** Daily points, oldest first. */
|
|
347
|
-
points: Array<{
|
|
348
|
-
date: string;
|
|
349
|
-
ga4: number | null;
|
|
350
|
-
vercel: number | null;
|
|
351
|
-
}>;
|
|
352
|
-
/** Accessible description of what the two lines are. */
|
|
353
|
-
label?: string;
|
|
354
|
-
}
|
|
355
|
-
/**
|
|
356
|
-
* Daily GA4 against Vercel, with axes, dated ticks and a hover readout.
|
|
357
|
-
*
|
|
358
|
-
* The shaded band between the lines is the point of the chart rather than decoration: it IS the
|
|
359
|
-
* measurement gap, and seeing where it opens is what distinguishes an incident from a standing
|
|
360
|
-
* difference. Darden's opened overnight on 2026-08-24 and stayed open for over a week, which no
|
|
361
|
-
* scalar on this panel could have shown.
|
|
362
|
-
*
|
|
363
|
-
* Inline SVG with no charting library — one dependency-free element in a Studio that already loads
|
|
364
|
-
* a great deal, and it renders on the server so the tests can assert on it. Strokes use
|
|
365
|
-
* currentColor so the whole thing follows the Studio's theme without a palette of its own.
|
|
366
|
-
*/
|
|
367
|
-
declare function TrendChart({ points, label }: TrendChartProps): React.ReactElement | null;
|
|
368
344
|
/** One column of a sortable table. */
|
|
369
345
|
interface SortColumn<Row> {
|
|
370
346
|
/** Stable key, also used as the sort key. */
|
|
@@ -638,4 +614,4 @@ interface VisitorInsightsPluginOptions {
|
|
|
638
614
|
*/
|
|
639
615
|
declare const visitorInsights: sanity.Plugin<VisitorInsightsPluginOptions>;
|
|
640
616
|
|
|
641
|
-
export { AcquisitionData, AcquisitionPanel, ChartData, type ChartDataProps, ComparisonBar, CrossSourceTimeline, type CrossSourceTimelineProps, DataHealthPanel, Delta, type DeltaProps, DiagnosticReport, DiagnosticsPanel, FunnelChart, JourneyData, JourneyPanel, MeasurementHealthData, DataHealthPanel as MeasurementHealthPanel, MetricFigure, MetricValue, NoticeList, OverviewPanel, type ProportionBar, ProportionChart, type ProportionChartProps, RangeKey, ReportEnvelope, ReportName, type ReportState, type Series, type SeriesPoint, type SortColumn, SortableTable, type SortableTableProps, type TimelineMarker,
|
|
617
|
+
export { AcquisitionData, AcquisitionPanel, ChartData, type ChartDataProps, ComparisonBar, CrossSourceTimeline, type CrossSourceTimelineProps, DataHealthPanel, Delta, type DeltaProps, DiagnosticReport, DiagnosticsPanel, FunnelChart, JourneyData, JourneyPanel, MeasurementHealthData, DataHealthPanel as MeasurementHealthPanel, MetricFigure, MetricValue, NoticeList, OverviewPanel, type ProportionBar, ProportionChart, type ProportionChartProps, RangeKey, ReportEnvelope, ReportName, type ReportState, type Series, type SeriesPoint, type SortColumn, SortableTable, type SortableTableProps, type TimelineMarker, TypefaceInterestData, TypefaceInterestPanel, type UseReportOptions, type ViewState, type VisitorInsightsPluginOptions, VisitorInsightsTool, type VisitorInsightsToolProps, decodeView, visitorInsights as default, encodeView, formatCount, formatMoney, formatPercent, knownShortfall, mergeIntoHash, useReport, visitorInsights };
|
package/dist/index.d.ts
CHANGED
|
@@ -341,30 +341,6 @@ interface NoticeListProps {
|
|
|
341
341
|
* Rendered in the panel rather than a README: a caveat nobody sees does not prevent a wrong read.
|
|
342
342
|
*/
|
|
343
343
|
declare function NoticeList({ notices }: NoticeListProps): React.ReactElement | null;
|
|
344
|
-
/** Props for TrendChart. */
|
|
345
|
-
interface TrendChartProps {
|
|
346
|
-
/** Daily points, oldest first. */
|
|
347
|
-
points: Array<{
|
|
348
|
-
date: string;
|
|
349
|
-
ga4: number | null;
|
|
350
|
-
vercel: number | null;
|
|
351
|
-
}>;
|
|
352
|
-
/** Accessible description of what the two lines are. */
|
|
353
|
-
label?: string;
|
|
354
|
-
}
|
|
355
|
-
/**
|
|
356
|
-
* Daily GA4 against Vercel, with axes, dated ticks and a hover readout.
|
|
357
|
-
*
|
|
358
|
-
* The shaded band between the lines is the point of the chart rather than decoration: it IS the
|
|
359
|
-
* measurement gap, and seeing where it opens is what distinguishes an incident from a standing
|
|
360
|
-
* difference. Darden's opened overnight on 2026-08-24 and stayed open for over a week, which no
|
|
361
|
-
* scalar on this panel could have shown.
|
|
362
|
-
*
|
|
363
|
-
* Inline SVG with no charting library — one dependency-free element in a Studio that already loads
|
|
364
|
-
* a great deal, and it renders on the server so the tests can assert on it. Strokes use
|
|
365
|
-
* currentColor so the whole thing follows the Studio's theme without a palette of its own.
|
|
366
|
-
*/
|
|
367
|
-
declare function TrendChart({ points, label }: TrendChartProps): React.ReactElement | null;
|
|
368
344
|
/** One column of a sortable table. */
|
|
369
345
|
interface SortColumn<Row> {
|
|
370
346
|
/** Stable key, also used as the sort key. */
|
|
@@ -638,4 +614,4 @@ interface VisitorInsightsPluginOptions {
|
|
|
638
614
|
*/
|
|
639
615
|
declare const visitorInsights: sanity.Plugin<VisitorInsightsPluginOptions>;
|
|
640
616
|
|
|
641
|
-
export { AcquisitionData, AcquisitionPanel, ChartData, type ChartDataProps, ComparisonBar, CrossSourceTimeline, type CrossSourceTimelineProps, DataHealthPanel, Delta, type DeltaProps, DiagnosticReport, DiagnosticsPanel, FunnelChart, JourneyData, JourneyPanel, MeasurementHealthData, DataHealthPanel as MeasurementHealthPanel, MetricFigure, MetricValue, NoticeList, OverviewPanel, type ProportionBar, ProportionChart, type ProportionChartProps, RangeKey, ReportEnvelope, ReportName, type ReportState, type Series, type SeriesPoint, type SortColumn, SortableTable, type SortableTableProps, type TimelineMarker,
|
|
617
|
+
export { AcquisitionData, AcquisitionPanel, ChartData, type ChartDataProps, ComparisonBar, CrossSourceTimeline, type CrossSourceTimelineProps, DataHealthPanel, Delta, type DeltaProps, DiagnosticReport, DiagnosticsPanel, FunnelChart, JourneyData, JourneyPanel, MeasurementHealthData, DataHealthPanel as MeasurementHealthPanel, MetricFigure, MetricValue, NoticeList, OverviewPanel, type ProportionBar, ProportionChart, type ProportionChartProps, RangeKey, ReportEnvelope, ReportName, type ReportState, type Series, type SeriesPoint, type SortColumn, SortableTable, type SortableTableProps, type TimelineMarker, TypefaceInterestData, TypefaceInterestPanel, type UseReportOptions, type ViewState, type VisitorInsightsPluginOptions, VisitorInsightsTool, type VisitorInsightsToolProps, decodeView, visitorInsights as default, encodeView, formatCount, formatMoney, formatPercent, knownShortfall, mergeIntoHash, useReport, visitorInsights };
|
package/dist/index.js
CHANGED
|
@@ -47,7 +47,6 @@ __export(index_exports, {
|
|
|
47
47
|
ProportionChart: () => ProportionChart,
|
|
48
48
|
REPORT_NAMES: () => REPORT_NAMES,
|
|
49
49
|
SortableTable: () => SortableTable,
|
|
50
|
-
TrendChart: () => TrendChart,
|
|
51
50
|
TypefaceInterestPanel: () => TypefaceInterestPanel,
|
|
52
51
|
VisitorInsightsTool: () => VisitorInsightsTool,
|
|
53
52
|
coverageForRange: () => coverageForRange,
|
|
@@ -578,18 +577,6 @@ var barTrack = {
|
|
|
578
577
|
background: "currentColor",
|
|
579
578
|
opacity: 0.12
|
|
580
579
|
};
|
|
581
|
-
var chartFrame = { position: "relative", width: "100%" };
|
|
582
|
-
var readout = {
|
|
583
|
-
position: "absolute",
|
|
584
|
-
top: 0,
|
|
585
|
-
right: 0,
|
|
586
|
-
padding: "6px 10px",
|
|
587
|
-
borderRadius: 3,
|
|
588
|
-
background: "var(--card-bg-color, rgba(0,0,0,0.55))",
|
|
589
|
-
border: "1px solid var(--card-border-color, rgba(128,128,128,0.35))",
|
|
590
|
-
pointerEvents: "none",
|
|
591
|
-
maxWidth: "70%"
|
|
592
|
-
};
|
|
593
580
|
var barHeader = {
|
|
594
581
|
display: "flex",
|
|
595
582
|
alignItems: "center",
|
|
@@ -597,12 +584,6 @@ var barHeader = {
|
|
|
597
584
|
gap: 12,
|
|
598
585
|
flexWrap: "wrap"
|
|
599
586
|
};
|
|
600
|
-
var legendRow = {
|
|
601
|
-
display: "flex",
|
|
602
|
-
gap: 12,
|
|
603
|
-
alignItems: "center",
|
|
604
|
-
flexWrap: "wrap"
|
|
605
|
-
};
|
|
606
587
|
var disclosure = {
|
|
607
588
|
appearance: "none",
|
|
608
589
|
background: "transparent",
|
|
@@ -651,185 +632,6 @@ function NoticeList({ notices }) {
|
|
|
651
632
|
)
|
|
652
633
|
] });
|
|
653
634
|
}
|
|
654
|
-
var CHART = { w: 760, h: 240, left: 52, right: 12, top: 16, bottom: 30 };
|
|
655
|
-
function niceCeiling(value) {
|
|
656
|
-
if (value <= 0) return 1;
|
|
657
|
-
const magnitude = 10 ** Math.floor(Math.log10(value));
|
|
658
|
-
const normalised = value / magnitude;
|
|
659
|
-
const step = normalised <= 1 ? 1 : normalised <= 2 ? 2 : normalised <= 5 ? 5 : 10;
|
|
660
|
-
return step * magnitude;
|
|
661
|
-
}
|
|
662
|
-
function shortDate(iso) {
|
|
663
|
-
const parsed = /* @__PURE__ */ new Date(`${iso}T00:00:00Z`);
|
|
664
|
-
if (Number.isNaN(parsed.getTime())) return iso;
|
|
665
|
-
return `${parsed.getUTCDate()} ${parsed.toLocaleString("en-GB", { month: "short", timeZone: "UTC" })}`;
|
|
666
|
-
}
|
|
667
|
-
function TrendChart({ points, label = "Daily pageviews, GA4 against Vercel" }) {
|
|
668
|
-
const [hovered, setHovered] = import_react2.default.useState(null);
|
|
669
|
-
if (points.length < 3) return null;
|
|
670
|
-
const values = points.flatMap((p) => [p.ga4, p.vercel]).filter((v) => typeof v === "number");
|
|
671
|
-
if (values.length === 0) return null;
|
|
672
|
-
const max = niceCeiling(Math.max(...values, 1));
|
|
673
|
-
const plotW = CHART.w - CHART.left - CHART.right;
|
|
674
|
-
const plotH = CHART.h - CHART.top - CHART.bottom;
|
|
675
|
-
const x = (i) => CHART.left + i / Math.max(1, points.length - 1) * plotW;
|
|
676
|
-
const y = (v) => CHART.top + plotH - v / max * plotH;
|
|
677
|
-
const line = (pick) => {
|
|
678
|
-
let d = "";
|
|
679
|
-
let penDown = false;
|
|
680
|
-
points.forEach((p, i) => {
|
|
681
|
-
const v = pick(p);
|
|
682
|
-
if (typeof v !== "number") {
|
|
683
|
-
penDown = false;
|
|
684
|
-
return;
|
|
685
|
-
}
|
|
686
|
-
d += `${penDown ? "L" : "M"}${x(i).toFixed(1)} ${y(v).toFixed(1)} `;
|
|
687
|
-
penDown = true;
|
|
688
|
-
});
|
|
689
|
-
return d.trim();
|
|
690
|
-
};
|
|
691
|
-
const bands = [];
|
|
692
|
-
let run = [];
|
|
693
|
-
const flushRun = () => {
|
|
694
|
-
if (run.length > 1) {
|
|
695
|
-
const top = run.map((i) => `${x(i).toFixed(1)} ${y(points[i].vercel).toFixed(1)}`);
|
|
696
|
-
const bottom = [...run].reverse().map((i) => `${x(i).toFixed(1)} ${y(points[i].ga4).toFixed(1)}`);
|
|
697
|
-
bands.push(`M${top.join(" L")} L${bottom.join(" L")} Z`);
|
|
698
|
-
}
|
|
699
|
-
run = [];
|
|
700
|
-
};
|
|
701
|
-
points.forEach((p, i) => {
|
|
702
|
-
if (typeof p.ga4 === "number" && typeof p.vercel === "number") run.push(i);
|
|
703
|
-
else flushRun();
|
|
704
|
-
});
|
|
705
|
-
flushRun();
|
|
706
|
-
const ticks = [0, 0.25, 0.5, 0.75, 1].map((f) => ({ value: max * f, y: y(max * f) }));
|
|
707
|
-
const labelEvery = Math.max(1, Math.ceil(points.length / 6));
|
|
708
|
-
const dateTicks = points.map((p, i) => ({ i, date: p.date })).filter(({ i }) => i % labelEvery === 0 || i === points.length - 1);
|
|
709
|
-
const active = hovered !== null ? points[hovered] : null;
|
|
710
|
-
const activeGap = active && typeof active.ga4 === "number" && typeof active.vercel === "number" && active.vercel > 0 ? (active.vercel - active.ga4) / active.vercel : null;
|
|
711
|
-
const onKeyDown = (event) => {
|
|
712
|
-
const last = points.length - 1;
|
|
713
|
-
const current = hovered ?? 0;
|
|
714
|
-
const move = (next) => {
|
|
715
|
-
event.preventDefault();
|
|
716
|
-
setHovered(Math.max(0, Math.min(last, next)));
|
|
717
|
-
};
|
|
718
|
-
if (event.key === "ArrowRight") return move(hovered === null ? 0 : current + 1);
|
|
719
|
-
if (event.key === "ArrowLeft") return move(hovered === null ? last : current - 1);
|
|
720
|
-
if (event.key === "Home") return move(0);
|
|
721
|
-
if (event.key === "End") return move(last);
|
|
722
|
-
if (event.key === "Escape") {
|
|
723
|
-
setHovered(null);
|
|
724
|
-
return;
|
|
725
|
-
}
|
|
726
|
-
};
|
|
727
|
-
const onMove = (event) => {
|
|
728
|
-
const box = event.currentTarget.getBoundingClientRect();
|
|
729
|
-
if (box.width === 0) return;
|
|
730
|
-
const svgX = (event.clientX - box.left) / box.width * CHART.w;
|
|
731
|
-
const ratio = (svgX - CHART.left) / plotW;
|
|
732
|
-
const index = Math.round(ratio * (points.length - 1));
|
|
733
|
-
setHovered(index >= 0 && index < points.length ? index : null);
|
|
734
|
-
};
|
|
735
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_sanity_ui_compat.Stack, { space: 3, children: [
|
|
736
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: chartFrame, children: [
|
|
737
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
738
|
-
"svg",
|
|
739
|
-
{
|
|
740
|
-
viewBox: `0 0 ${CHART.w} ${CHART.h}`,
|
|
741
|
-
width: "100%",
|
|
742
|
-
style: { display: "block", height: "auto" },
|
|
743
|
-
role: "img",
|
|
744
|
-
"aria-label": `${label}, ${points[0]?.date} to ${points[points.length - 1]?.date}. Peak ${formatCount(max)} pageviews in a day.`,
|
|
745
|
-
onMouseMove: onMove,
|
|
746
|
-
onMouseLeave: () => setHovered(null),
|
|
747
|
-
onKeyDown,
|
|
748
|
-
onBlur: () => setHovered(null),
|
|
749
|
-
tabIndex: 0,
|
|
750
|
-
"aria-describedby": active ? "trend-readout" : void 0,
|
|
751
|
-
children: [
|
|
752
|
-
ticks.map((tick) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { children: [
|
|
753
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
754
|
-
"line",
|
|
755
|
-
{
|
|
756
|
-
x1: CHART.left,
|
|
757
|
-
x2: CHART.w - CHART.right,
|
|
758
|
-
y1: tick.y,
|
|
759
|
-
y2: tick.y,
|
|
760
|
-
stroke: "currentColor",
|
|
761
|
-
strokeOpacity: tick.value === 0 ? 0.35 : 0.12,
|
|
762
|
-
strokeWidth: "1"
|
|
763
|
-
}
|
|
764
|
-
),
|
|
765
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
766
|
-
"text",
|
|
767
|
-
{
|
|
768
|
-
x: CHART.left - 8,
|
|
769
|
-
y: tick.y + 4,
|
|
770
|
-
textAnchor: "end",
|
|
771
|
-
fontSize: "11",
|
|
772
|
-
fill: "currentColor",
|
|
773
|
-
fillOpacity: "0.55",
|
|
774
|
-
children: formatCount(tick.value)
|
|
775
|
-
}
|
|
776
|
-
)
|
|
777
|
-
] }, tick.value)),
|
|
778
|
-
dateTicks.map(({ i, date }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
779
|
-
"text",
|
|
780
|
-
{
|
|
781
|
-
x: x(i),
|
|
782
|
-
y: CHART.h - 10,
|
|
783
|
-
textAnchor: "middle",
|
|
784
|
-
fontSize: "11",
|
|
785
|
-
fill: "currentColor",
|
|
786
|
-
fillOpacity: "0.55",
|
|
787
|
-
children: shortDate(date)
|
|
788
|
-
},
|
|
789
|
-
date
|
|
790
|
-
)),
|
|
791
|
-
bands.map((d) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d, fill: "currentColor", fillOpacity: "0.09", stroke: "none" }, d.slice(0, 24))),
|
|
792
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: line((p) => p.vercel), fill: "none", stroke: "currentColor", strokeOpacity: "0.9", strokeWidth: "2" }),
|
|
793
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: line((p) => p.ga4), fill: "none", stroke: "currentColor", strokeOpacity: "0.9", strokeWidth: "2", strokeDasharray: "5 3" }),
|
|
794
|
-
hovered !== null && active && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { children: [
|
|
795
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
796
|
-
"line",
|
|
797
|
-
{
|
|
798
|
-
x1: x(hovered),
|
|
799
|
-
x2: x(hovered),
|
|
800
|
-
y1: CHART.top,
|
|
801
|
-
y2: CHART.top + plotH,
|
|
802
|
-
stroke: "currentColor",
|
|
803
|
-
strokeOpacity: "0.4",
|
|
804
|
-
strokeWidth: "1"
|
|
805
|
-
}
|
|
806
|
-
),
|
|
807
|
-
typeof active.vercel === "number" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: x(hovered), cy: y(active.vercel), r: "4", fill: "currentColor" }),
|
|
808
|
-
typeof active.ga4 === "number" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: x(hovered), cy: y(active.ga4), r: "4", fill: "currentColor" })
|
|
809
|
-
] })
|
|
810
|
-
]
|
|
811
|
-
}
|
|
812
|
-
),
|
|
813
|
-
active && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: readout, id: "trend-readout", role: "status", "aria-live": "polite", children: [
|
|
814
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_sanity_ui_compat.Text, { size: 1, weight: "medium", children: shortDate(active.date) }),
|
|
815
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_sanity_ui_compat.Text, { size: 1, muted: true, children: [
|
|
816
|
-
"Vercel ",
|
|
817
|
-
typeof active.vercel === "number" ? formatCount(active.vercel) : "\u2014",
|
|
818
|
-
" \xB7 ",
|
|
819
|
-
"GA4 ",
|
|
820
|
-
typeof active.ga4 === "number" ? formatCount(active.ga4) : "\u2014",
|
|
821
|
-
activeGap !== null ? ` \xB7 gap ${formatPercent(activeGap, 0)}` : ""
|
|
822
|
-
] })
|
|
823
|
-
] })
|
|
824
|
-
] }),
|
|
825
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: legendRow, children: [
|
|
826
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_sanity_ui_compat.Text, { size: 0, muted: true, children: "\u2501\u2501 Vercel" }),
|
|
827
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_sanity_ui_compat.Text, { size: 0, muted: true, children: "\u2504\u2504 GA4" }),
|
|
828
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_sanity_ui_compat.Text, { size: 0, muted: true, children: "shaded band is the gap" }),
|
|
829
|
-
!active && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_sanity_ui_compat.Text, { size: 0, muted: true, children: "hover, or focus and use arrow keys, for a day" })
|
|
830
|
-
] })
|
|
831
|
-
] });
|
|
832
|
-
}
|
|
833
635
|
function SortableTable({
|
|
834
636
|
caption,
|
|
835
637
|
columns,
|
|
@@ -1598,7 +1400,7 @@ function CrossSourceTimeline({ series, markers = [], currency, onBrush }) {
|
|
|
1598
1400
|
m.label
|
|
1599
1401
|
] }, m.label))
|
|
1600
1402
|
] }),
|
|
1601
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style:
|
|
1403
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: legendRow, children: [
|
|
1602
1404
|
series.some((row) => row.shortfall) && // Hover is not available on touch and not reachable by keyboard, so the reveal
|
|
1603
1405
|
// has an explicit control too. Without it the detail would exist only for people
|
|
1604
1406
|
// using a mouse.
|
|
@@ -1655,7 +1457,7 @@ var revealButton = {
|
|
|
1655
1457
|
cursor: "pointer",
|
|
1656
1458
|
whiteSpace: "nowrap"
|
|
1657
1459
|
};
|
|
1658
|
-
var
|
|
1460
|
+
var legendRow = {
|
|
1659
1461
|
display: "flex",
|
|
1660
1462
|
gap: 14,
|
|
1661
1463
|
flexWrap: "wrap",
|
|
@@ -2806,15 +2608,21 @@ function PanelTabs({ value, onChange }) {
|
|
|
2806
2608
|
}) });
|
|
2807
2609
|
}
|
|
2808
2610
|
function CoverageRibbon({ ratio }) {
|
|
2809
|
-
if (ratio === null
|
|
2611
|
+
if (ratio === null) {
|
|
2612
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_sanity_ui_compat4.Text, { size: 0, muted: true, children: "Every figure on this tab comes from Google Analytics. How much of your traffic it is seeing has not been checked for this window \u2014 open Overview or Data health to measure it." });
|
|
2613
|
+
}
|
|
2614
|
+
if (ratio < 0.2) return null;
|
|
2810
2615
|
const seen = Math.round((1 - ratio) * 100);
|
|
2616
|
+
const multiplier = seen > 0 ? Math.round(100 / seen) : null;
|
|
2811
2617
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_sanity_ui_compat4.Card, { padding: 3, radius: 2, tone: ratio > 0.6 ? "critical" : "caution", border: true, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_sanity_ui_compat4.Text, { size: 1, children: [
|
|
2812
|
-
"Every figure on this tab comes from Google Analytics, which is seeing
|
|
2618
|
+
"Every figure on this tab comes from Google Analytics, which is seeing roughly ",
|
|
2813
2619
|
seen,
|
|
2814
|
-
"% of this site\u2019s traffic in this window \u2014 so the real numbers are
|
|
2620
|
+
"% of this site\u2019s traffic in this window \u2014 so the real numbers are",
|
|
2815
2621
|
" ",
|
|
2816
|
-
|
|
2817
|
-
" these
|
|
2622
|
+
multiplier === null ? "many times" : `several times`,
|
|
2623
|
+
" these",
|
|
2624
|
+
multiplier !== null && multiplier > 1 ? ` (very roughly ${multiplier}\xD7)` : "",
|
|
2625
|
+
". Data health explains why, and how uncertain that is."
|
|
2818
2626
|
] }) });
|
|
2819
2627
|
}
|
|
2820
2628
|
function ReadyReport({
|
|
@@ -3287,7 +3095,6 @@ var index_default = visitorInsights;
|
|
|
3287
3095
|
ProportionChart,
|
|
3288
3096
|
REPORT_NAMES,
|
|
3289
3097
|
SortableTable,
|
|
3290
|
-
TrendChart,
|
|
3291
3098
|
TypefaceInterestPanel,
|
|
3292
3099
|
VisitorInsightsTool,
|
|
3293
3100
|
coverageForRange,
|