@liiift-studio/sanity-visitor-insights 0.28.0 → 0.30.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 +68 -9
- package/dist/index.d.ts +68 -9
- package/dist/index.js +245 -58
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +242 -58
- package/dist/index.mjs.map +1 -1
- package/dist/{ranges-D1A9JY7h.d.mts → ranges-B3BWyG3q.d.mts} +12 -4
- package/dist/{ranges-D1A9JY7h.d.ts → ranges-B3BWyG3q.d.ts} +12 -4
- package/dist/server.d.mts +2 -2
- package/dist/server.d.ts +2 -2
- package/dist/server.js +6 -5
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +6 -5
- package/dist/server.mjs.map +1 -1
- package/package.json +1 -1
- package/src/core/capture.ts +13 -5
- package/src/index.ts +1 -0
- package/src/server/reports/acquisition.ts +22 -8
- package/src/server/reports/measurementHealth.ts +2 -1
- package/src/studio/CrossSourceTimeline.tsx +219 -9
- package/src/studio/Figure.tsx +10 -1
- package/src/studio/VisitorInsightsTool.tsx +39 -4
- package/src/studio/panels.test.tsx +243 -6
- package/src/studio/panels.tsx +54 -6
- package/src/studio/urlState.ts +118 -0
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, c as MeasurementHealthData, D as DiagnosticReport, J as JourneyData, T as TypefaceInterestData } from './ranges-
|
|
4
|
-
export { C as CaptureBasis, d as CaptureEstimate, e as CaptureModel, f as CheckStatus, g as Coverage, h as CrossSourceDay, i as DailyPoint, j as DateRange, k as DiagnosticCheck, E as EmailCampaign, l as EventCutover, m as JourneyOutcome, n as JourneyStep, L as LandingPage, o as LicenceTierRow, P as PREEXISTING, p as REPORT_NAMES, q as ReportError, S as SiteAnalyticsConfig, r as SourceName, s as SourceRow, t as SourceStatus, u as TimelineEvent, v as TypefaceInterestRow, U as UnavailableReason, w as coverageForRange, x as estimated, y as isReportName, z as ok, B as partial, F as previousRange, G as resolveRange, H as unavailable, I as validateSiteConfig, K as valueOrNull } from './ranges-
|
|
3
|
+
import { R as ReportEnvelope, a as ReportName, b as RangeKey, M as MetricValue, A as AcquisitionData, c as MeasurementHealthData, D as DiagnosticReport, J as JourneyData, T as TypefaceInterestData } from './ranges-B3BWyG3q.mjs';
|
|
4
|
+
export { C as CaptureBasis, d as CaptureEstimate, e as CaptureModel, f as CheckStatus, g as Coverage, h as CrossSourceDay, i as DailyPoint, j as DateRange, k as DiagnosticCheck, E as EmailCampaign, l as EventCutover, m as JourneyOutcome, n as JourneyStep, L as LandingPage, o as LicenceTierRow, P as PREEXISTING, p as REPORT_NAMES, q as ReportError, S as SiteAnalyticsConfig, r as SourceName, s as SourceRow, t as SourceStatus, u as TimelineEvent, v as TypefaceInterestRow, U as UnavailableReason, w as coverageForRange, x as estimated, y as isReportName, z as ok, B as partial, F as previousRange, G as resolveRange, H as unavailable, I as validateSiteConfig, K as valueOrNull } from './ranges-B3BWyG3q.mjs';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Data hook for the Studio panels.
|
|
@@ -100,6 +100,62 @@ interface VisitorInsightsToolComponentProps extends Partial<VisitorInsightsToolP
|
|
|
100
100
|
}
|
|
101
101
|
declare function VisitorInsightsTool(props: VisitorInsightsToolComponentProps): React.ReactElement;
|
|
102
102
|
|
|
103
|
+
/**
|
|
104
|
+
* The tool's view, in the URL — so a finding can be sent to someone.
|
|
105
|
+
*
|
|
106
|
+
* Every piece of state here was component-local: tab, range, and the custom window. A Studio
|
|
107
|
+
* reload, a browser back, or an accidental navigation discarded the whole investigation, and
|
|
108
|
+
* "Acquisition, 24 August to 7 September" — the exact view in which someone notices the thing worth
|
|
109
|
+
* noticing — could not be handed to a colleague or returned to by the person who found it. There is
|
|
110
|
+
* a "Copy as CSV" in this tool precisely because sharing a finding is the real task; the view
|
|
111
|
+
* itself was the one thing that could not be shared.
|
|
112
|
+
*
|
|
113
|
+
* The HASH, not the path or the query. Sanity's own router owns the path, and writing to it would
|
|
114
|
+
* fight the Studio for control of navigation; the hash is unclaimed, survives a reload, is carried
|
|
115
|
+
* by a copied link, and is ignored by every server. The value is namespaced because other tools in
|
|
116
|
+
* the same Studio may want the same trick.
|
|
117
|
+
*
|
|
118
|
+
* Everything here is a pure string transformation, so it is testable without a DOM — which matters,
|
|
119
|
+
* because the alternative is a feature whose only proof is clicking around a deployed Studio.
|
|
120
|
+
*/
|
|
121
|
+
/** The part of the tool's state worth putting in a link. */
|
|
122
|
+
interface ViewState {
|
|
123
|
+
/** Tab id, e.g. `overview`. */
|
|
124
|
+
tab?: string;
|
|
125
|
+
/** Range key, e.g. `week` or `custom`. */
|
|
126
|
+
range?: string;
|
|
127
|
+
/** Custom window start, ISO date. Only meaningful when `range` is `custom`. */
|
|
128
|
+
from?: string;
|
|
129
|
+
/** Custom window end, ISO date. */
|
|
130
|
+
to?: string;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Serialise a view to the hash fragment it should occupy.
|
|
134
|
+
*
|
|
135
|
+
* Returns an empty string for an empty view, so a default view leaves the URL clean rather than
|
|
136
|
+
* decorating it with state nobody set.
|
|
137
|
+
*
|
|
138
|
+
* @param view - the state to encode
|
|
139
|
+
*/
|
|
140
|
+
declare function encodeView(view: ViewState): string;
|
|
141
|
+
/**
|
|
142
|
+
* Read a view out of a hash fragment.
|
|
143
|
+
*
|
|
144
|
+
* Every field is validated and an unrecognised one is dropped rather than defaulted, so a truncated
|
|
145
|
+
* or hand-edited link degrades to whatever it could parse instead of failing or, worse, silently
|
|
146
|
+
* requesting a window nobody chose.
|
|
147
|
+
*
|
|
148
|
+
* @param hash - `window.location.hash`, with or without its leading `#`
|
|
149
|
+
*/
|
|
150
|
+
declare function decodeView(hash: string): ViewState;
|
|
151
|
+
/**
|
|
152
|
+
* Replace our fragment in a hash, preserving anyone else's.
|
|
153
|
+
*
|
|
154
|
+
* @param hash - the current hash
|
|
155
|
+
* @param view - the state to write
|
|
156
|
+
*/
|
|
157
|
+
declare function mergeIntoHash(hash: string, view: ViewState): string;
|
|
158
|
+
|
|
103
159
|
/**
|
|
104
160
|
* Shared renderers for metric values and comparison bars.
|
|
105
161
|
*
|
|
@@ -426,6 +482,15 @@ interface Series {
|
|
|
426
482
|
* event, on a date, of a size. Days with nothing draw nothing, which is the truth.
|
|
427
483
|
*/
|
|
428
484
|
mark?: 'line' | 'events';
|
|
485
|
+
/**
|
|
486
|
+
* A fixed y domain, instead of scaling the row to its own peak.
|
|
487
|
+
*
|
|
488
|
+
* Small multiples normally scale each row to itself, which is right for quantities whose
|
|
489
|
+
* absolute size is not comparable between rows. It is wrong for a proportion: a coverage row
|
|
490
|
+
* auto-scaled to its own maximum would redraw 100% at whatever the best day happened to be, so
|
|
491
|
+
* a site running at a flat 20% would show a full-height line and read as healthy.
|
|
492
|
+
*/
|
|
493
|
+
domain?: [number, number];
|
|
429
494
|
points: SeriesPoint[];
|
|
430
495
|
/**
|
|
431
496
|
* What a lossier source saw of the same thing.
|
|
@@ -465,12 +530,6 @@ interface CrossSourceTimelineProps {
|
|
|
465
530
|
*/
|
|
466
531
|
onBrush?: (start: string, end: string) => void;
|
|
467
532
|
}
|
|
468
|
-
/**
|
|
469
|
-
* The cross-source timeline.
|
|
470
|
-
*
|
|
471
|
-
* Renders nothing rather than an empty frame when there is not enough to plot — two points cannot
|
|
472
|
-
* show a shape, and an axis with one dot on it invites a reading it cannot support.
|
|
473
|
-
*/
|
|
474
533
|
declare function CrossSourceTimeline({ series, markers, currency, onBrush }: CrossSourceTimelineProps): React.ReactElement | null;
|
|
475
534
|
|
|
476
535
|
/**
|
|
@@ -579,4 +638,4 @@ interface VisitorInsightsPluginOptions {
|
|
|
579
638
|
*/
|
|
580
639
|
declare const visitorInsights: sanity.Plugin<VisitorInsightsPluginOptions>;
|
|
581
640
|
|
|
582
|
-
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, TrendChart, TypefaceInterestData, TypefaceInterestPanel, type UseReportOptions, type VisitorInsightsPluginOptions, VisitorInsightsTool, type VisitorInsightsToolProps, visitorInsights as default, formatCount, formatMoney, formatPercent, knownShortfall, useReport, visitorInsights };
|
|
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, TrendChart, 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
|
@@ -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, c as MeasurementHealthData, D as DiagnosticReport, J as JourneyData, T as TypefaceInterestData } from './ranges-
|
|
4
|
-
export { C as CaptureBasis, d as CaptureEstimate, e as CaptureModel, f as CheckStatus, g as Coverage, h as CrossSourceDay, i as DailyPoint, j as DateRange, k as DiagnosticCheck, E as EmailCampaign, l as EventCutover, m as JourneyOutcome, n as JourneyStep, L as LandingPage, o as LicenceTierRow, P as PREEXISTING, p as REPORT_NAMES, q as ReportError, S as SiteAnalyticsConfig, r as SourceName, s as SourceRow, t as SourceStatus, u as TimelineEvent, v as TypefaceInterestRow, U as UnavailableReason, w as coverageForRange, x as estimated, y as isReportName, z as ok, B as partial, F as previousRange, G as resolveRange, H as unavailable, I as validateSiteConfig, K as valueOrNull } from './ranges-
|
|
3
|
+
import { R as ReportEnvelope, a as ReportName, b as RangeKey, M as MetricValue, A as AcquisitionData, c as MeasurementHealthData, D as DiagnosticReport, J as JourneyData, T as TypefaceInterestData } from './ranges-B3BWyG3q.js';
|
|
4
|
+
export { C as CaptureBasis, d as CaptureEstimate, e as CaptureModel, f as CheckStatus, g as Coverage, h as CrossSourceDay, i as DailyPoint, j as DateRange, k as DiagnosticCheck, E as EmailCampaign, l as EventCutover, m as JourneyOutcome, n as JourneyStep, L as LandingPage, o as LicenceTierRow, P as PREEXISTING, p as REPORT_NAMES, q as ReportError, S as SiteAnalyticsConfig, r as SourceName, s as SourceRow, t as SourceStatus, u as TimelineEvent, v as TypefaceInterestRow, U as UnavailableReason, w as coverageForRange, x as estimated, y as isReportName, z as ok, B as partial, F as previousRange, G as resolveRange, H as unavailable, I as validateSiteConfig, K as valueOrNull } from './ranges-B3BWyG3q.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Data hook for the Studio panels.
|
|
@@ -100,6 +100,62 @@ interface VisitorInsightsToolComponentProps extends Partial<VisitorInsightsToolP
|
|
|
100
100
|
}
|
|
101
101
|
declare function VisitorInsightsTool(props: VisitorInsightsToolComponentProps): React.ReactElement;
|
|
102
102
|
|
|
103
|
+
/**
|
|
104
|
+
* The tool's view, in the URL — so a finding can be sent to someone.
|
|
105
|
+
*
|
|
106
|
+
* Every piece of state here was component-local: tab, range, and the custom window. A Studio
|
|
107
|
+
* reload, a browser back, or an accidental navigation discarded the whole investigation, and
|
|
108
|
+
* "Acquisition, 24 August to 7 September" — the exact view in which someone notices the thing worth
|
|
109
|
+
* noticing — could not be handed to a colleague or returned to by the person who found it. There is
|
|
110
|
+
* a "Copy as CSV" in this tool precisely because sharing a finding is the real task; the view
|
|
111
|
+
* itself was the one thing that could not be shared.
|
|
112
|
+
*
|
|
113
|
+
* The HASH, not the path or the query. Sanity's own router owns the path, and writing to it would
|
|
114
|
+
* fight the Studio for control of navigation; the hash is unclaimed, survives a reload, is carried
|
|
115
|
+
* by a copied link, and is ignored by every server. The value is namespaced because other tools in
|
|
116
|
+
* the same Studio may want the same trick.
|
|
117
|
+
*
|
|
118
|
+
* Everything here is a pure string transformation, so it is testable without a DOM — which matters,
|
|
119
|
+
* because the alternative is a feature whose only proof is clicking around a deployed Studio.
|
|
120
|
+
*/
|
|
121
|
+
/** The part of the tool's state worth putting in a link. */
|
|
122
|
+
interface ViewState {
|
|
123
|
+
/** Tab id, e.g. `overview`. */
|
|
124
|
+
tab?: string;
|
|
125
|
+
/** Range key, e.g. `week` or `custom`. */
|
|
126
|
+
range?: string;
|
|
127
|
+
/** Custom window start, ISO date. Only meaningful when `range` is `custom`. */
|
|
128
|
+
from?: string;
|
|
129
|
+
/** Custom window end, ISO date. */
|
|
130
|
+
to?: string;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Serialise a view to the hash fragment it should occupy.
|
|
134
|
+
*
|
|
135
|
+
* Returns an empty string for an empty view, so a default view leaves the URL clean rather than
|
|
136
|
+
* decorating it with state nobody set.
|
|
137
|
+
*
|
|
138
|
+
* @param view - the state to encode
|
|
139
|
+
*/
|
|
140
|
+
declare function encodeView(view: ViewState): string;
|
|
141
|
+
/**
|
|
142
|
+
* Read a view out of a hash fragment.
|
|
143
|
+
*
|
|
144
|
+
* Every field is validated and an unrecognised one is dropped rather than defaulted, so a truncated
|
|
145
|
+
* or hand-edited link degrades to whatever it could parse instead of failing or, worse, silently
|
|
146
|
+
* requesting a window nobody chose.
|
|
147
|
+
*
|
|
148
|
+
* @param hash - `window.location.hash`, with or without its leading `#`
|
|
149
|
+
*/
|
|
150
|
+
declare function decodeView(hash: string): ViewState;
|
|
151
|
+
/**
|
|
152
|
+
* Replace our fragment in a hash, preserving anyone else's.
|
|
153
|
+
*
|
|
154
|
+
* @param hash - the current hash
|
|
155
|
+
* @param view - the state to write
|
|
156
|
+
*/
|
|
157
|
+
declare function mergeIntoHash(hash: string, view: ViewState): string;
|
|
158
|
+
|
|
103
159
|
/**
|
|
104
160
|
* Shared renderers for metric values and comparison bars.
|
|
105
161
|
*
|
|
@@ -426,6 +482,15 @@ interface Series {
|
|
|
426
482
|
* event, on a date, of a size. Days with nothing draw nothing, which is the truth.
|
|
427
483
|
*/
|
|
428
484
|
mark?: 'line' | 'events';
|
|
485
|
+
/**
|
|
486
|
+
* A fixed y domain, instead of scaling the row to its own peak.
|
|
487
|
+
*
|
|
488
|
+
* Small multiples normally scale each row to itself, which is right for quantities whose
|
|
489
|
+
* absolute size is not comparable between rows. It is wrong for a proportion: a coverage row
|
|
490
|
+
* auto-scaled to its own maximum would redraw 100% at whatever the best day happened to be, so
|
|
491
|
+
* a site running at a flat 20% would show a full-height line and read as healthy.
|
|
492
|
+
*/
|
|
493
|
+
domain?: [number, number];
|
|
429
494
|
points: SeriesPoint[];
|
|
430
495
|
/**
|
|
431
496
|
* What a lossier source saw of the same thing.
|
|
@@ -465,12 +530,6 @@ interface CrossSourceTimelineProps {
|
|
|
465
530
|
*/
|
|
466
531
|
onBrush?: (start: string, end: string) => void;
|
|
467
532
|
}
|
|
468
|
-
/**
|
|
469
|
-
* The cross-source timeline.
|
|
470
|
-
*
|
|
471
|
-
* Renders nothing rather than an empty frame when there is not enough to plot — two points cannot
|
|
472
|
-
* show a shape, and an axis with one dot on it invites a reading it cannot support.
|
|
473
|
-
*/
|
|
474
533
|
declare function CrossSourceTimeline({ series, markers, currency, onBrush }: CrossSourceTimelineProps): React.ReactElement | null;
|
|
475
534
|
|
|
476
535
|
/**
|
|
@@ -579,4 +638,4 @@ interface VisitorInsightsPluginOptions {
|
|
|
579
638
|
*/
|
|
580
639
|
declare const visitorInsights: sanity.Plugin<VisitorInsightsPluginOptions>;
|
|
581
640
|
|
|
582
|
-
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, TrendChart, TypefaceInterestData, TypefaceInterestPanel, type UseReportOptions, type VisitorInsightsPluginOptions, VisitorInsightsTool, type VisitorInsightsToolProps, visitorInsights as default, formatCount, formatMoney, formatPercent, knownShortfall, useReport, visitorInsights };
|
|
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, TrendChart, TypefaceInterestData, TypefaceInterestPanel, type UseReportOptions, type ViewState, type VisitorInsightsPluginOptions, VisitorInsightsTool, type VisitorInsightsToolProps, decodeView, visitorInsights as default, encodeView, formatCount, formatMoney, formatPercent, knownShortfall, mergeIntoHash, useReport, visitorInsights };
|