@antelopejs/dms-marketing 0.6.1 → 0.7.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.
Files changed (181) hide show
  1. package/dist/config.d.ts +3 -0
  2. package/dist/config.js +11 -0
  3. package/dist/config.js.map +1 -1
  4. package/dist/data-api/websites.d.ts +10 -4
  5. package/dist/data-api/websites.js +79 -3
  6. package/dist/data-api/websites.js.map +1 -1
  7. package/dist/db/models/page_snapshots.model.d.ts +2 -0
  8. package/dist/db/models/page_snapshots.model.js +6 -0
  9. package/dist/db/models/page_snapshots.model.js.map +1 -1
  10. package/dist/db/models/websites.model.d.ts +1 -0
  11. package/dist/db/models/websites.model.js +9 -0
  12. package/dist/db/models/websites.model.js.map +1 -1
  13. package/dist/db/tables/page_snapshots.table.d.ts +1 -0
  14. package/dist/db/tables/page_snapshots.table.js +4 -0
  15. package/dist/db/tables/page_snapshots.table.js.map +1 -1
  16. package/dist/db/tables/websites.table.d.ts +2 -0
  17. package/dist/db/tables/websites.table.js +4 -0
  18. package/dist/db/tables/websites.table.js.map +1 -1
  19. package/dist/frontend-module.d.ts +6 -0
  20. package/dist/frontend-module.js +46 -0
  21. package/dist/frontend-module.js.map +1 -0
  22. package/dist/index.js +3 -11
  23. package/dist/index.js.map +1 -1
  24. package/dist/pages/acquisition/page.d.ts +1 -0
  25. package/dist/pages/acquisition/page.js +9 -4
  26. package/dist/pages/acquisition/page.js.map +1 -1
  27. package/dist/pages/blocks.d.ts +11 -2
  28. package/dist/pages/blocks.js +43 -5
  29. package/dist/pages/blocks.js.map +1 -1
  30. package/dist/pages/funnel/page.d.ts +1 -0
  31. package/dist/pages/funnel/page.js +1 -0
  32. package/dist/pages/funnel/page.js.map +1 -1
  33. package/dist/pages/funnels/page.d.ts +1 -0
  34. package/dist/pages/funnels/page.js +4 -2
  35. package/dist/pages/funnels/page.js.map +1 -1
  36. package/dist/pages/overview/page.d.ts +1 -0
  37. package/dist/pages/overview/page.js +5 -6
  38. package/dist/pages/overview/page.js.map +1 -1
  39. package/dist/pages/pages/page.d.ts +1 -0
  40. package/dist/pages/pages/page.js +1 -0
  41. package/dist/pages/pages/page.js.map +1 -1
  42. package/dist/pages/settings/form.js +1 -0
  43. package/dist/pages/settings/form.js.map +1 -1
  44. package/dist/pages/websites/page.d.ts +2 -3
  45. package/dist/pages/websites/page.js +63 -5
  46. package/dist/pages/websites/page.js.map +1 -1
  47. package/dist/routes/dashboard-tracking.js +5 -1
  48. package/dist/routes/dashboard-tracking.js.map +1 -1
  49. package/dist/routes/funnels.d.ts +2 -0
  50. package/dist/routes/funnels.js +6 -5
  51. package/dist/routes/funnels.js.map +1 -1
  52. package/dist/routes/public-endpoints.js +1 -1
  53. package/dist/routes/public-endpoints.js.map +1 -1
  54. package/dist/routes/snapshot.d.ts +1 -1
  55. package/dist/routes/snapshot.js +30 -13
  56. package/dist/routes/snapshot.js.map +1 -1
  57. package/dist/routes/stats.d.ts +10 -4
  58. package/dist/routes/stats.js +77 -23
  59. package/dist/routes/stats.js.map +1 -1
  60. package/dist/routes/websites.d.ts +5 -1
  61. package/dist/routes/websites.js +31 -13
  62. package/dist/routes/websites.js.map +1 -1
  63. package/dist/services/acquisition-report.d.ts +1 -0
  64. package/dist/services/acquisition-report.js +1 -0
  65. package/dist/services/acquisition-report.js.map +1 -1
  66. package/dist/services/collect.js +7 -2
  67. package/dist/services/collect.js.map +1 -1
  68. package/dist/services/dashboard-tracking.d.ts +7 -14
  69. package/dist/services/dashboard-tracking.js +42 -26
  70. package/dist/services/dashboard-tracking.js.map +1 -1
  71. package/dist/services/funnels-table.d.ts +3 -2
  72. package/dist/services/funnels-table.js +9 -9
  73. package/dist/services/funnels-table.js.map +1 -1
  74. package/dist/services/heatmap.d.ts +6 -0
  75. package/dist/services/heatmap.js +82 -17
  76. package/dist/services/heatmap.js.map +1 -1
  77. package/dist/services/index.d.ts +1 -0
  78. package/dist/services/index.js +1 -0
  79. package/dist/services/index.js.map +1 -1
  80. package/dist/services/prune.js +6 -1
  81. package/dist/services/prune.js.map +1 -1
  82. package/dist/services/realtime.d.ts +3 -0
  83. package/dist/services/realtime.js +49 -0
  84. package/dist/services/realtime.js.map +1 -0
  85. package/dist/services/request-body.d.ts +1 -0
  86. package/dist/services/request-body.js +18 -0
  87. package/dist/services/request-body.js.map +1 -1
  88. package/dist/services/sessionize.d.ts +1 -0
  89. package/dist/services/sessionize.js +9 -0
  90. package/dist/services/sessionize.js.map +1 -1
  91. package/dist/services/snapshots.d.ts +28 -1
  92. package/dist/services/snapshots.js +147 -26
  93. package/dist/services/snapshots.js.map +1 -1
  94. package/dist/services/tenant-website.d.ts +11 -0
  95. package/dist/services/tenant-website.js +27 -5
  96. package/dist/services/tenant-website.js.map +1 -1
  97. package/dist/services/website-report.d.ts +5 -0
  98. package/dist/services/website-report.js +13 -1
  99. package/dist/services/website-report.js.map +1 -1
  100. package/dist/services/workspace-scope.d.ts +31 -0
  101. package/dist/services/workspace-scope.js +72 -0
  102. package/dist/services/workspace-scope.js.map +1 -0
  103. package/dist/types/constants.d.ts +7 -0
  104. package/dist/types/constants.js +8 -1
  105. package/dist/types/constants.js.map +1 -1
  106. package/dist/types/events.d.ts +25 -25
  107. package/dist/types/snapshots.d.ts +29 -29
  108. package/dist/types/snapshots.js +1 -1
  109. package/dist/types/snapshots.js.map +1 -1
  110. package/dist/utils/funnel-steps-type.d.ts +13 -13
  111. package/frontend-vue/app/components/ChannelsCard.vue +19 -2
  112. package/frontend-vue/app/components/Context.vue +50 -376
  113. package/frontend-vue/app/components/FunnelBuilder.vue +28 -22
  114. package/frontend-vue/app/components/FunnelFigure.vue +15 -2
  115. package/frontend-vue/app/components/FunnelReport.vue +3 -0
  116. package/frontend-vue/app/components/FunnelTemplates.vue +15 -13
  117. package/frontend-vue/app/components/InstallGuide.vue +1 -1
  118. package/frontend-vue/app/components/PagePreview.vue +330 -74
  119. package/frontend-vue/app/components/PagesExplorer.vue +230 -85
  120. package/frontend-vue/app/components/TopListTabs.vue +51 -18
  121. package/frontend-vue/app/components/WebsiteCard.vue +394 -0
  122. package/frontend-vue/app/components/WebsiteCreate.vue +159 -0
  123. package/frontend-vue/app/components/WebsitePicker.vue +210 -0
  124. package/frontend-vue/app/components/WebsiteSettings.vue +539 -0
  125. package/frontend-vue/app/components/WorkspaceScope.vue +119 -0
  126. package/frontend-vue/app/composables/useContextWebsite.ts +105 -0
  127. package/frontend-vue/app/composables/useCopyDraft.ts +47 -0
  128. package/frontend-vue/app/composables/useMarketingApi.ts +92 -4
  129. package/frontend-vue/app/composables/useMarketingReads.ts +32 -23
  130. package/frontend-vue/app/composables/useMarketingRoutes.ts +25 -2
  131. package/frontend-vue/app/composables/useRecordCrumb.ts +17 -0
  132. package/frontend-vue/app/composables/useSnapshotFrame.ts +35 -1
  133. package/frontend-vue/app/utils/anchor-drift.ts +58 -0
  134. package/frontend-vue/app/utils/drift-dismissals.ts +20 -0
  135. package/frontend-vue/app/utils/fill-height.ts +141 -0
  136. package/frontend-vue/app/utils/format.ts +21 -2
  137. package/frontend-vue/app/utils/funnel-draft.ts +22 -0
  138. package/frontend-vue/app/utils/heatmap.ts +17 -0
  139. package/frontend-vue/app/utils/page-snapshot.ts +75 -0
  140. package/frontend-vue/app/utils/snapshot-options.ts +148 -0
  141. package/frontend-vue/app/utils/snapshotScrollRoot.ts +93 -0
  142. package/frontend-vue/app/utils/website-card.ts +93 -0
  143. package/frontend-vue/app/utils/website-purge.ts +95 -0
  144. package/frontend-vue/app/utils/website-settings.ts +121 -0
  145. package/frontend-vue/app/utils/website-state.ts +93 -0
  146. package/frontend-vue/app/utils/workspace-scope.ts +51 -0
  147. package/frontend-vue/i18n/locales/marketing-en-GB.json +112 -36
  148. package/frontend-vue/i18n/locales/marketing-fr-FR.json +112 -36
  149. package/frontend-vue/package.json +1 -1
  150. package/frontend-vue/tests/anchor-drift.test.ts +59 -0
  151. package/frontend-vue/tests/build-flags.test.ts +38 -0
  152. package/frontend-vue/tests/context-bar.test.ts +226 -0
  153. package/frontend-vue/tests/copy-draft.test.ts +64 -0
  154. package/frontend-vue/tests/drift-dismissals.test.ts +12 -0
  155. package/frontend-vue/tests/fill-height.test.ts +110 -0
  156. package/frontend-vue/tests/format.test.ts +14 -0
  157. package/frontend-vue/tests/funnel-draft.test.ts +37 -0
  158. package/frontend-vue/tests/heatmap.test.ts +25 -0
  159. package/frontend-vue/tests/install-guide.test.ts +25 -0
  160. package/frontend-vue/tests/marketing-reads.test.ts +20 -6
  161. package/frontend-vue/tests/page-snapshot.test.ts +62 -0
  162. package/frontend-vue/tests/record-crumb.test.ts +43 -0
  163. package/frontend-vue/tests/registration.test.ts +4 -1
  164. package/frontend-vue/tests/routes.test.ts +21 -0
  165. package/frontend-vue/tests/save-funnel.test.ts +47 -0
  166. package/frontend-vue/tests/server-parity.test.ts +3 -0
  167. package/frontend-vue/tests/snapshot-options.test.ts +148 -0
  168. package/frontend-vue/tests/snapshot-scroll-root.test.ts +84 -0
  169. package/frontend-vue/tests/stubs/frontend-module.ts +5 -1
  170. package/frontend-vue/tests/top-list-tabs.test.ts +158 -0
  171. package/frontend-vue/tests/website-card.test.ts +119 -0
  172. package/frontend-vue/tests/website-purge.test.ts +70 -0
  173. package/frontend-vue/tests/website-settings.test.ts +133 -0
  174. package/frontend-vue/tests/website-state.test.ts +96 -0
  175. package/frontend-vue/tests/workspace-scope-control.test.ts +113 -0
  176. package/frontend-vue/tests/workspace-scope.test.ts +55 -0
  177. package/package.json +5 -4
  178. package/skills/dms-marketing/SKILL.md +47 -6
  179. package/static/snapshot.js +539 -48
  180. package/static/tracker.js +154 -5
  181. package/frontend-vue/app/components/WebsitesGrid.vue +0 -812
package/static/tracker.js CHANGED
@@ -38,6 +38,15 @@
38
38
  * (static/snapshot.js) or nothing — so a visit never serializes a page
39
39
  * nobody will keep, and a page is captured about once a day however busy
40
40
  * it is. Off unless the website opted in.
41
+ *
42
+ * Scroll root: an app shell often keeps its document still and scrolls an
43
+ * inner container instead (a dashboard panel, a sidebar layout). When the
44
+ * document does not scroll, the page's scroll root is the element marked
45
+ * `data-marketing-scroll-root` if there is one, else the largest visible
46
+ * element scrolling vertically (overflow-y auto or scroll, content taller
47
+ * than its box) that covers most of the window; the document otherwise.
48
+ * Scroll depth is measured on it, and click positions are taken in its
49
+ * content, as if the page were unrolled — which is how a capture draws it.
41
50
  */
42
51
  (() => {
43
52
  /** Global the tracker route injects the module settings through. */
@@ -69,6 +78,20 @@
69
78
  const SCROLL_MEASURE_DELAY_MS = 1000;
70
79
  /** Where a keyboard-activated click is anchored inside its element. */
71
80
  const ELEMENT_CENTER = 0.5;
81
+ /** Names the element that scrolls the page, where the document does not. */
82
+ const SCROLL_ROOT_ATTRIBUTE = "data-marketing-scroll-root";
83
+ /** Share of the window an inner scroll container must cover to stand for
84
+ * the page: less is a list, a code block or a dropdown. */
85
+ const SCROLL_ROOT_COVERAGE = 0.5;
86
+ /** Points of the window (fractions of its width and height) probed for an
87
+ * inner scroll container: one covering most of the window holds several. */
88
+ const SCROLL_ROOT_PROBES = [
89
+ [0.5, 0.5],
90
+ [0.5, 0.25],
91
+ [0.5, 0.75],
92
+ [0.25, 0.5],
93
+ [0.75, 0.5],
94
+ ];
72
95
 
73
96
  // --- Public API -----------------------------------------------------------
74
97
 
@@ -267,6 +290,7 @@
267
290
  pageExcluded = isExcludedPath(lastPath);
268
291
  scrolledUrl = currentUrl();
269
292
  maxScrollDepth = -1;
293
+ scrollRootElement = null;
270
294
  if (!websiteId || pageExcluded) {
271
295
  return;
272
296
  }
@@ -298,15 +322,97 @@
298
322
  }
299
323
  });
300
324
 
325
+ // --- Scroll root (see the header) ----------------------------------------
326
+
327
+ function documentScrolls() {
328
+ const root = document.documentElement;
329
+ return root.scrollHeight - root.clientHeight > 1;
330
+ }
331
+
332
+ function scrollsVertically(element) {
333
+ if (element.scrollHeight - element.clientHeight <= 1) {
334
+ return false;
335
+ }
336
+ const overflow = getComputedStyle(element).overflowY;
337
+ return overflow === "auto" || overflow === "scroll";
338
+ }
339
+
340
+ /** Area of the element's box inside the window. */
341
+ function visibleArea(element) {
342
+ const box = element.getBoundingClientRect();
343
+ const width = Math.min(box.right, innerWidth) - Math.max(box.left, 0);
344
+ const height = Math.min(box.bottom, innerHeight) - Math.max(box.top, 0);
345
+ return width > 0 && height > 0 ? width * height : 0;
346
+ }
347
+
348
+ /**
349
+ * The element scrolling the page, or null when it is the document. Found
350
+ * from what lies under a few points of the window, never by walking the
351
+ * whole tree: a container covering most of the window holds them.
352
+ */
353
+ function findScrollRoot() {
354
+ if (documentScrolls()) {
355
+ return null;
356
+ }
357
+ const marked = document.querySelector(`[${SCROLL_ROOT_ATTRIBUTE}]`);
358
+ if (marked) {
359
+ return marked;
360
+ }
361
+ if (typeof document.elementFromPoint !== "function") {
362
+ return null;
363
+ }
364
+ const visited = new Set();
365
+ let best = null;
366
+ let bestArea = innerWidth * innerHeight * SCROLL_ROOT_COVERAGE;
367
+ for (const [fx, fy] of SCROLL_ROOT_PROBES) {
368
+ let node = document.elementFromPoint(innerWidth * fx, innerHeight * fy);
369
+ // An ancestor already visited was checked with all of its own.
370
+ for (; node && !visited.has(node); node = node.parentElement) {
371
+ visited.add(node);
372
+ if (
373
+ node === document.body ||
374
+ node === document.documentElement ||
375
+ !scrollsVertically(node)
376
+ ) {
377
+ continue;
378
+ }
379
+ const area = visibleArea(node);
380
+ if (area > bestArea) {
381
+ best = node;
382
+ bestArea = area;
383
+ }
384
+ }
385
+ }
386
+ return best;
387
+ }
388
+
389
+ /** Kept while it stays in the page and the document still does not
390
+ * scroll; looked for again otherwise — and on every new view. */
391
+ let scrollRootElement = null;
392
+
393
+ function scrollRoot() {
394
+ if (
395
+ !scrollRootElement ||
396
+ !scrollRootElement.isConnected ||
397
+ documentScrolls()
398
+ ) {
399
+ scrollRootElement = findScrollRoot();
400
+ }
401
+ return scrollRootElement;
402
+ }
403
+
301
404
  // --- Scroll depth (max reached per page, flushed on leave) ----------------
302
405
 
303
406
  function currentScrollDepth() {
304
- const root = document.documentElement;
407
+ const inner = scrollRoot();
408
+ const root = inner || document.documentElement;
305
409
  const scrollable = root.scrollHeight - root.clientHeight;
306
410
  if (scrollable <= 0) {
307
411
  return PERCENT_SCALE;
308
412
  }
309
- const scrolled = root.scrollTop || document.body.scrollTop || 0;
413
+ const scrolled = inner
414
+ ? inner.scrollTop
415
+ : root.scrollTop || document.body.scrollTop || 0;
310
416
  return Math.min(
311
417
  PERCENT_SCALE,
312
418
  Math.round((scrolled / scrollable) * PERCENT_SCALE),
@@ -320,7 +426,12 @@
320
426
  }
321
427
  }
322
428
 
323
- window.addEventListener("scroll", measureScrollDepth, { passive: true });
429
+ // Captured on the document: an element's scroll does not bubble, and the
430
+ // window never hears it.
431
+ document.addEventListener("scroll", measureScrollDepth, {
432
+ capture: true,
433
+ passive: true,
434
+ });
324
435
 
325
436
  /**
326
437
  * Every sampled view reports a depth, scrolled or not: what shows without
@@ -442,6 +553,38 @@
442
553
  };
443
554
  }
444
555
 
556
+ /**
557
+ * Vertical position of a point in the page's content, and the content's
558
+ * height: with an inner scroll root, the range it hides is unrolled — a
559
+ * click on something inside it moves down by its scroll offset, one on
560
+ * something under it (a footer below the panel) by the whole hidden range
561
+ * — so `dy` reads the same however far the visitor had scrolled it, and
562
+ * lines up with a capture of the whole page. Beside it (a sidebar) or
563
+ * above it (a header), nothing moves.
564
+ */
565
+ function contentPosition(target, point) {
566
+ const height = document.documentElement.scrollHeight;
567
+ const root = scrollRoot();
568
+ if (!root) {
569
+ return { y: point.pageY, height: height };
570
+ }
571
+ const hidden = root.scrollHeight - root.clientHeight;
572
+ let y = point.pageY;
573
+ if (root.contains(target)) {
574
+ y += root.scrollTop;
575
+ } else {
576
+ const box = root.getBoundingClientRect();
577
+ if (
578
+ point.clientY >= box.bottom &&
579
+ point.clientX >= box.left &&
580
+ point.clientX < box.right
581
+ ) {
582
+ y += hidden;
583
+ }
584
+ }
585
+ return { y: y, height: height + hidden };
586
+ }
587
+
445
588
  document.addEventListener(
446
589
  "click",
447
590
  (event) => {
@@ -455,6 +598,7 @@
455
598
  }
456
599
  const doc = document.documentElement;
457
600
  const point = clickPoint(target, event);
601
+ const content = contentPosition(target, point);
458
602
  enqueue(
459
603
  Object.assign(base(), {
460
604
  kind: "click",
@@ -463,7 +607,7 @@
463
607
  x: normalized(point.clientX, innerWidth),
464
608
  y: normalized(point.clientY, innerHeight),
465
609
  dx: normalized(point.pageX, doc.scrollWidth),
466
- dy: normalized(point.pageY, doc.scrollHeight),
610
+ dy: normalized(content.y, content.height),
467
611
  selector: shortSelector(target),
468
612
  },
469
613
  elementAnchor(target, point),
@@ -508,12 +652,17 @@
508
652
  website: websiteId,
509
653
  endpoint: snapshotEndpoint,
510
654
  path: path,
655
+ // Looked for at capture time, the page as it is then.
656
+ scrollRoot: findScrollRoot,
511
657
  };
512
658
  const loader = document.createElement("script");
513
659
  loader.async = true;
514
660
  loader.src =
515
661
  `${hostUrl}/api/marketing/snapshot.js?website=${encodeURIComponent(websiteId)}` +
516
- `&path=${encodeURIComponent(path)}&width=${innerWidth}`;
662
+ `&path=${encodeURIComponent(path)}&width=${innerWidth}` +
663
+ // Lets the backend replace a capture taken before captures marked the
664
+ // scroll root, instead of waiting for it to age.
665
+ (scrollRoot() ? "&root=1" : "");
517
666
  const settle = () => loader.remove();
518
667
  loader.addEventListener("load", settle);
519
668
  loader.addEventListener("error", settle);