@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
@@ -0,0 +1,210 @@
1
+ <script setup lang="ts">
2
+ import { computed } from 'vue'
3
+ import { useI18n } from '#dms/frontend-module'
4
+ import type { ContextWebsite } from '../composables/useMarketingContext'
5
+ import { useContextWebsite } from '../composables/useContextWebsite'
6
+ import { useMarketingNow } from '../composables/useMarketingNow'
7
+ import { installLink } from '../composables/useMarketingRoutes'
8
+ import { initials, utcDayStart } from '../utils/format'
9
+ import {
10
+ WEBSITE_STATE_DOTS,
11
+ websiteDisplayState,
12
+ websiteStateLine,
13
+ websiteStateShort,
14
+ } from '../utils/website-state'
15
+ import { MAX_PERIOD_DAYS, MS_PER_DAY, PERIOD_SCOPE } from '../constants'
16
+
17
+ /**
18
+ * The leading child of an analytics page's toolbar (`marketingToolbar()`):
19
+ * the website picker, its state (a dot and the age of its last event, the
20
+ * full line in a tooltip) and the period's hints. The toolbar puts Direct /
21
+ * Pause and the period after it.
22
+ *
23
+ * The website is the page's `?website=` (`useContextWebsite`): a pick saves
24
+ * it and writes the URL, which the blocks read through a `{{query.website}}`
25
+ * token. The websites' last events are read again on the module's arrivals,
26
+ * through the page's live gate (nothing while paused).
27
+ */
28
+ const props = withDefaults(
29
+ defineProps<{
30
+ periodScope?: string
31
+ realtimeTopic?: string
32
+ }>(),
33
+ {
34
+ periodScope: PERIOD_SCOPE,
35
+ realtimeTopic: undefined,
36
+ },
37
+ )
38
+
39
+ /** How often the ages the picker shows ("1 min ago") move: display only. */
40
+ const CLOCK_TICK_MS = 15_000
41
+
42
+ const { t, locale } = useI18n()
43
+ const { size } = usePageToolbarSize()
44
+ const {
45
+ context,
46
+ failed,
47
+ websites,
48
+ selectedId,
49
+ selected,
50
+ switching,
51
+ select,
52
+ reload,
53
+ } = useContextWebsite()
54
+
55
+ usePageLiveRefresh(() => void reload(), {
56
+ realtimeTopic: props.realtimeTopic,
57
+ })
58
+
59
+ const now = useMarketingNow(CLOCK_TICK_MS)
60
+ const period = usePeriodScope(props.periodScope)
61
+
62
+ /** A custom range longer than the routes read: only its last days are shown. */
63
+ const cutHint = computed(() => {
64
+ const range = selected.value ? period.value?.range : null
65
+ if (!range) {
66
+ return ''
67
+ }
68
+ const days = Math.round(
69
+ (range.to.getTime() - range.from.getTime()) / MS_PER_DAY,
70
+ )
71
+ return days > MAX_PERIOD_DAYS
72
+ ? t('page.marketing.context.range_cut', { days: MAX_PERIOD_DAYS })
73
+ : ''
74
+ })
75
+
76
+ const displayState = (site: ContextWebsite) =>
77
+ websiteDisplayState(site, now.value)
78
+
79
+ const stateLine = (site: ContextWebsite) =>
80
+ websiteStateLine(site, now.value, t, locale.value)
81
+
82
+ const stateShort = (site: ContextWebsite) =>
83
+ websiteStateShort(site, now.value, t, locale.value)
84
+
85
+ const websiteItems = computed(() => [
86
+ websites.value.map((site) => ({
87
+ label: site.name,
88
+ description: site.domain,
89
+ type: 'checkbox' as const,
90
+ checked: site.id === selectedId.value,
91
+ slot: 'website' as const,
92
+ site,
93
+ onSelect: () => void select(site.id),
94
+ })),
95
+ [
96
+ {
97
+ label: t('page.marketing.context.add_website'),
98
+ icon: 'i-ph-plus',
99
+ to: installLink(),
100
+ },
101
+ ],
102
+ ])
103
+
104
+ /**
105
+ * The statistics are kept per UTC day: where the reader's midnight is not
106
+ * UTC's, the state's tooltip says when their days really start.
107
+ */
108
+ const utcHint = computed(() => {
109
+ // The reader's zone: the browser's, which a server render reads from its
110
+ // cookie.
111
+ const time = utcDayStart(now.value, locale.value, readerTimeZone())
112
+ return time ? t('page.marketing.context.utc_days', { time }) : ''
113
+ })
114
+
115
+ /** The full state line and the UTC days: the compact state's name. */
116
+ const stateHint = computed(() =>
117
+ selected.value
118
+ ? [stateLine(selected.value), utcHint.value].filter(Boolean).join('. ')
119
+ : '',
120
+ )
121
+ </script>
122
+
123
+ <template>
124
+ <USkeleton v-if="!context && !failed" class="h-7 w-72" />
125
+ <!-- One group, tighter than the toolbar's gaps: with the live toggle and
126
+ the period, the bar stays on one line at desktop width. -->
127
+ <div
128
+ v-else-if="selected"
129
+ class="flex min-w-0 flex-wrap items-center gap-2"
130
+ data-website-picker
131
+ >
132
+ <UDropdownMenu :items="websiteItems" :content="{ align: 'start' }">
133
+ <UButton
134
+ color="neutral"
135
+ variant="outline"
136
+ :size="size"
137
+ trailing-icon="i-ph-caret-up-down"
138
+ :loading="switching"
139
+ :aria-label="t('page.marketing.context.switch_website')"
140
+ >
141
+ <span
142
+ class="grid size-5 place-items-center rounded bg-primary/15 font-mono text-[10px] font-semibold text-(--ui-color-primary-800) dark:text-primary"
143
+ >
144
+ {{ initials(selected.name) }}
145
+ </span>
146
+ <span class="font-semibold">{{ selected.name }}</span>
147
+ </UButton>
148
+ <template #website="{ item }">
149
+ <span
150
+ class="grid size-6 shrink-0 place-items-center rounded bg-primary/15 font-mono text-[10px] font-semibold text-(--ui-color-primary-800) dark:text-primary"
151
+ >
152
+ {{ initials(item.site.name) }}
153
+ </span>
154
+ <span class="min-w-0 flex-1 text-left">
155
+ <span class="block truncate text-sm font-medium text-highlighted">
156
+ {{ item.site.name }}
157
+ </span>
158
+ <span class="flex min-w-0 items-center gap-1.5 text-xs text-dimmed">
159
+ <span
160
+ class="size-1.5 shrink-0 rounded-full"
161
+ :class="WEBSITE_STATE_DOTS[displayState(item.site)]"
162
+ aria-hidden="true"
163
+ />
164
+ <span class="truncate font-mono">{{ item.site.domain }}</span>
165
+ <span class="shrink-0">· {{ stateLine(item.site) }}</span>
166
+ </span>
167
+ </span>
168
+ <UIcon
169
+ v-if="item.checked"
170
+ name="i-ph-check"
171
+ class="size-4 shrink-0 text-primary"
172
+ />
173
+ </template>
174
+ </UDropdownMenu>
175
+
176
+ <UTooltip>
177
+ <span
178
+ class="flex items-center gap-1.5 text-xs whitespace-nowrap text-muted tabular-nums"
179
+ role="status"
180
+ tabindex="0"
181
+ :aria-label="stateHint"
182
+ >
183
+ <span
184
+ class="size-2 rounded-full"
185
+ :class="WEBSITE_STATE_DOTS[displayState(selected)]"
186
+ aria-hidden="true"
187
+ />
188
+ <span aria-hidden="true">{{ stateShort(selected) }}</span>
189
+ </span>
190
+ <template #content>
191
+ <span class="grid max-w-72 gap-1">
192
+ <span>{{ stateLine(selected) }}</span>
193
+ <span v-if="utcHint" class="text-dimmed">{{ utcHint }}</span>
194
+ </span>
195
+ </template>
196
+ </UTooltip>
197
+
198
+ <span
199
+ v-if="cutHint"
200
+ class="flex items-center gap-1 text-xs text-warning"
201
+ role="status"
202
+ >
203
+ <UIcon name="i-ph-warning" class="size-3.5 shrink-0" />
204
+ {{ cutHint }}
205
+ </span>
206
+ </div>
207
+ <span v-else-if="!failed" class="text-sm text-muted">
208
+ {{ t('page.marketing.context.no_website') }}
209
+ </span>
210
+ </template>