@agent-native/core 0.120.2 → 0.120.4

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 (278) hide show
  1. package/corpus/README.md +3 -3
  2. package/corpus/core/CHANGELOG.md +28 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/cli/context-xray-local.ts +1 -1
  5. package/corpus/core/src/cli/index.ts +63 -18
  6. package/corpus/core/src/cli/skills.ts +5 -0
  7. package/corpus/core/src/cli/telemetry.ts +118 -1
  8. package/corpus/core/src/client/AgentPanel.tsx +10 -0
  9. package/corpus/core/src/client/CommandMenu.tsx +13 -1
  10. package/corpus/core/src/client/agent-page/AgentTabsPage.tsx +39 -4
  11. package/corpus/core/src/client/analytics.ts +13 -0
  12. package/corpus/core/src/client/error-capture.ts +6 -1
  13. package/corpus/core/src/client/extensions/ExtensionsListPage.tsx +12 -5
  14. package/corpus/core/src/client/extensions/agent-native-extension-runtime.ts +1 -1
  15. package/corpus/core/src/client/navigation/index.ts +2 -0
  16. package/corpus/core/src/client/org/OrgSwitcher.tsx +14 -32
  17. package/corpus/core/src/client/settings/ExtensionsSettingsContent.tsx +1 -1
  18. package/corpus/core/src/extensions/theme.ts +1 -1
  19. package/corpus/core/src/localization/default-messages.ts +2 -0
  20. package/corpus/core/src/server/core-routes-plugin.ts +10 -1
  21. package/corpus/core/src/server/framework-request-handler.ts +17 -26
  22. package/corpus/core/src/styles/agent-native.css +13 -0
  23. package/corpus/core/src/templates/chat/app/components/layout/Layout.tsx +3 -0
  24. package/corpus/core/src/templates/chat/app/components/layout/Sidebar.tsx +78 -45
  25. package/corpus/core/src/templates/chat/app/global.css +1 -1
  26. package/corpus/core/src/templates/default/app/global.css +1 -1
  27. package/corpus/core/src/tracking/error-capture.ts +151 -0
  28. package/corpus/core/src/tracking/index.ts +5 -0
  29. package/corpus/templates/analytics/app/components/dashboard/CumulativeNetChart.tsx +1 -1
  30. package/corpus/templates/analytics/app/components/dashboard/DashboardHistoryPanel.tsx +1 -4
  31. package/corpus/templates/analytics/app/components/dashboard/DashboardPanelSkeleton.tsx +1 -1
  32. package/corpus/templates/analytics/app/components/dashboard/DataTable.tsx +1 -1
  33. package/corpus/templates/analytics/app/components/dashboard/DateRangePicker.tsx +2 -2
  34. package/corpus/templates/analytics/app/components/dashboard/MetricCard.tsx +1 -1
  35. package/corpus/templates/analytics/app/components/dashboard/RecentActivity.tsx +1 -1
  36. package/corpus/templates/analytics/app/components/dashboard/RevenueChart.tsx +1 -1
  37. package/corpus/templates/analytics/app/components/dashboard/RevenueComparisonChart.tsx +1 -1
  38. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +41 -9
  39. package/corpus/templates/analytics/app/components/dashboard/StatsCard.tsx +1 -1
  40. package/corpus/templates/analytics/app/components/dashboard/TimeSeriesChart.tsx +1 -1
  41. package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +2 -0
  42. package/corpus/templates/analytics/app/components/layout/Layout.tsx +28 -14
  43. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +152 -124
  44. package/corpus/templates/analytics/app/global.css +5 -5
  45. package/corpus/templates/analytics/app/lib/dashboard-report-capture.ts +42 -0
  46. package/corpus/templates/analytics/app/pages/adhoc/_shared/KpiChart.tsx +1 -1
  47. package/corpus/templates/analytics/app/pages/adhoc/explorer/components/ChartTypePicker.tsx +1 -1
  48. package/corpus/templates/analytics/app/pages/adhoc/explorer/components/DateRangePicker.tsx +1 -1
  49. package/corpus/templates/analytics/app/pages/adhoc/explorer/components/EventRow.tsx +1 -1
  50. package/corpus/templates/analytics/app/pages/adhoc/explorer/components/SqlPreview.tsx +2 -2
  51. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/DashboardFilterBar.tsx +3 -3
  52. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/EmailReportDialog.tsx +2 -2
  53. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +1 -1
  54. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +1 -1
  55. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +162 -51
  56. package/corpus/templates/analytics/app/root.tsx +28 -0
  57. package/corpus/templates/analytics/changelog/2026-07-24-analytics-charts-now-explain-slow-loads-and-offer-a-direct-r.md +6 -0
  58. package/corpus/templates/analytics/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  59. package/corpus/templates/analytics/changelog/2026-07-24-daily-dashboard-emails-now-load-signed-reports-more-reliably.md +6 -0
  60. package/corpus/templates/analytics/changelog/2026-07-24-manage-agent-is-clearly-marked-as-a-link-to-its-dedicated-pa.md +6 -0
  61. package/corpus/templates/analytics/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  62. package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +1 -1
  63. package/corpus/templates/analytics/server/db/schema.ts +5 -0
  64. package/corpus/templates/analytics/server/jobs/dashboard-report.ts +21 -0
  65. package/corpus/templates/analytics/server/lib/canonical-first-party-dashboard-repair.ts +11 -0
  66. package/corpus/templates/analytics/server/lib/dashboard-report-subscriptions.ts +54 -0
  67. package/corpus/templates/analytics/server/lib/dashboard-report.ts +235 -26
  68. package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +4 -1
  69. package/corpus/templates/analytics/server/plugins/db.ts +9 -0
  70. package/corpus/templates/analytics/shared/dashboard-report-timeouts.ts +1 -1
  71. package/corpus/templates/assets/app/components/asset/AssetPreviewDialog.tsx +376 -0
  72. package/corpus/templates/assets/app/components/create/RecentDraftsSection.tsx +14 -4
  73. package/corpus/templates/assets/app/components/layout/Layout.tsx +5 -0
  74. package/corpus/templates/assets/app/components/layout/Sidebar.tsx +118 -74
  75. package/corpus/templates/assets/app/global.css +1 -1
  76. package/corpus/templates/assets/app/i18n-data.ts +10 -0
  77. package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +99 -10
  78. package/corpus/templates/assets/app/routes/library.tsx +21 -198
  79. package/corpus/templates/assets/changelog/2026-07-21-unified-asset-preview-click-any-asset-to-open-one-preview-wi.md +6 -0
  80. package/corpus/templates/assets/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  81. package/corpus/templates/assets/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  82. package/corpus/templates/brain/app/components/layout/Layout.tsx +3 -0
  83. package/corpus/templates/brain/app/components/layout/Sidebar.tsx +76 -43
  84. package/corpus/templates/brain/app/global.css +1 -1
  85. package/corpus/templates/brain/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  86. package/corpus/templates/brain/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  87. package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +67 -52
  88. package/corpus/templates/calendar/app/global.css +1 -1
  89. package/corpus/templates/calendar/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  90. package/corpus/templates/calendar/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  91. package/corpus/templates/chat/app/components/layout/Layout.tsx +3 -0
  92. package/corpus/templates/chat/app/components/layout/Sidebar.tsx +78 -45
  93. package/corpus/templates/chat/app/global.css +1 -1
  94. package/corpus/templates/chat/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  95. package/corpus/templates/chat/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  96. package/corpus/templates/clips/app/components/library/library-layout.tsx +65 -31
  97. package/corpus/templates/clips/app/components/library/organization-switcher.tsx +2 -2
  98. package/corpus/templates/clips/app/components/player/video-player.tsx +16 -1
  99. package/corpus/templates/clips/app/global.css +1 -1
  100. package/corpus/templates/clips/app/hooks/use-view-tracking.ts +55 -12
  101. package/corpus/templates/clips/app/routes/embed.$shareId.tsx +6 -5
  102. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +7 -7
  103. package/corpus/templates/clips/app/routes/share.$shareId.tsx +6 -5
  104. package/corpus/templates/clips/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  105. package/corpus/templates/clips/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  106. package/corpus/templates/clips/server/plugins/db.ts +113 -68
  107. package/corpus/templates/content/actions/update-document.ts +145 -91
  108. package/corpus/templates/content/app/components/editor/CommentComposer.tsx +4 -1
  109. package/corpus/templates/content/app/components/editor/CommentsSidebar.tsx +366 -164
  110. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +51 -28
  111. package/corpus/templates/content/app/components/editor/database/sidebar.tsx +19 -8
  112. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +66 -42
  113. package/corpus/templates/content/app/global.css +1 -1
  114. package/corpus/templates/content/app/i18n-data.ts +15 -0
  115. package/corpus/templates/content/changelog/2026-07-23-shared-pages-now-keep-durable-content-visible-and-comment-th.md +6 -0
  116. package/corpus/templates/content/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  117. package/corpus/templates/content/changelog/2026-07-24-comment-drafts-now-stay-open-when-saving-fails-and-long-live.md +6 -0
  118. package/corpus/templates/content/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  119. package/corpus/templates/design/actions/update-file.ts +85 -18
  120. package/corpus/templates/design/app/components/layout/Sidebar.tsx +65 -30
  121. package/corpus/templates/design/app/entry.client.tsx +14 -1
  122. package/corpus/templates/design/app/global.css +1 -1
  123. package/corpus/templates/design/app/lib/design-save-outbox.ts +39 -0
  124. package/corpus/templates/design/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  125. package/corpus/templates/design/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  126. package/corpus/templates/dispatch/app/global.css +1 -1
  127. package/corpus/templates/dispatch/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  128. package/corpus/templates/dispatch/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  129. package/corpus/templates/forms/app/components/layout/Layout.tsx +3 -0
  130. package/corpus/templates/forms/app/components/layout/Sidebar.tsx +72 -37
  131. package/corpus/templates/forms/app/global.css +1 -1
  132. package/corpus/templates/forms/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  133. package/corpus/templates/forms/changelog/2026-07-24-forms-sidebar-actions-now-keep-search-language-feedback-and-.md +6 -0
  134. package/corpus/templates/forms/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  135. package/corpus/templates/macros/app/components/DailyProgress.tsx +5 -5
  136. package/corpus/templates/macros/app/components/ExerciseCard.tsx +2 -2
  137. package/corpus/templates/macros/app/components/MealCard.tsx +2 -2
  138. package/corpus/templates/macros/app/components/WeightCard.tsx +2 -2
  139. package/corpus/templates/macros/app/components/layout/AppLayout.tsx +56 -29
  140. package/corpus/templates/macros/app/components/ui/button.tsx +1 -2
  141. package/corpus/templates/macros/app/components/ui/card.tsx +1 -1
  142. package/corpus/templates/macros/app/global.css +1 -1
  143. package/corpus/templates/macros/app/routes/_index.tsx +1 -1
  144. package/corpus/templates/macros/app/routes/analytics.tsx +4 -7
  145. package/corpus/templates/macros/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  146. package/corpus/templates/macros/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  147. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +125 -37
  148. package/corpus/templates/mail/app/global.css +1 -1
  149. package/corpus/templates/mail/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  150. package/corpus/templates/mail/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  151. package/corpus/templates/plan/app/components/layout/Layout.tsx +3 -0
  152. package/corpus/templates/plan/app/components/layout/Sidebar.tsx +90 -60
  153. package/corpus/templates/plan/app/global.css +1 -1
  154. package/corpus/templates/plan/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  155. package/corpus/templates/plan/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  156. package/corpus/templates/slides/app/components/layout/Sidebar.tsx +69 -32
  157. package/corpus/templates/slides/app/global.css +1 -1
  158. package/corpus/templates/slides/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  159. package/corpus/templates/slides/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  160. package/corpus/templates/tasks/app/global.css +1 -1
  161. package/corpus/templates/tasks/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  162. package/corpus/toolkit/CHANGELOG.md +14 -0
  163. package/corpus/toolkit/README.md +8 -1
  164. package/corpus/toolkit/agent-native.eject.json +1 -1
  165. package/corpus/toolkit/package.json +1 -1
  166. package/corpus/toolkit/src/app-shell/index.ts +1 -0
  167. package/corpus/toolkit/src/app-shell/sidebar-footer-actions.tsx +48 -0
  168. package/corpus/toolkit/src/chat-history.css +52 -1
  169. package/corpus/toolkit/src/design-system/default-adapter.tsx +1 -1
  170. package/corpus/toolkit/src/editor/useCollabReconcile.ts +83 -15
  171. package/corpus/toolkit/src/ui/button.tsx +1 -2
  172. package/corpus/toolkit/src/ui/card.tsx +1 -1
  173. package/corpus/toolkit/src/ui/table.tsx +4 -11
  174. package/dist/cli/context-xray-local.js +1 -1
  175. package/dist/cli/context-xray-local.js.map +1 -1
  176. package/dist/cli/index.js +56 -17
  177. package/dist/cli/index.js.map +1 -1
  178. package/dist/cli/skills.d.ts.map +1 -1
  179. package/dist/cli/skills.js +5 -0
  180. package/dist/cli/skills.js.map +1 -1
  181. package/dist/cli/telemetry.d.ts +7 -0
  182. package/dist/cli/telemetry.d.ts.map +1 -1
  183. package/dist/cli/telemetry.js +91 -1
  184. package/dist/cli/telemetry.js.map +1 -1
  185. package/dist/client/AgentPanel.d.ts +7 -1
  186. package/dist/client/AgentPanel.d.ts.map +1 -1
  187. package/dist/client/AgentPanel.js +2 -2
  188. package/dist/client/AgentPanel.js.map +1 -1
  189. package/dist/client/CommandMenu.d.ts +2 -0
  190. package/dist/client/CommandMenu.d.ts.map +1 -1
  191. package/dist/client/CommandMenu.js +12 -1
  192. package/dist/client/CommandMenu.js.map +1 -1
  193. package/dist/client/agent-page/AgentTabsPage.d.ts +4 -0
  194. package/dist/client/agent-page/AgentTabsPage.d.ts.map +1 -1
  195. package/dist/client/agent-page/AgentTabsPage.js +8 -4
  196. package/dist/client/agent-page/AgentTabsPage.js.map +1 -1
  197. package/dist/client/analytics.d.ts.map +1 -1
  198. package/dist/client/analytics.js +7 -0
  199. package/dist/client/analytics.js.map +1 -1
  200. package/dist/client/error-capture.d.ts.map +1 -1
  201. package/dist/client/error-capture.js +8 -1
  202. package/dist/client/error-capture.js.map +1 -1
  203. package/dist/client/extensions/ExtensionsListPage.d.ts.map +1 -1
  204. package/dist/client/extensions/ExtensionsListPage.js +2 -2
  205. package/dist/client/extensions/ExtensionsListPage.js.map +1 -1
  206. package/dist/client/extensions/agent-native-extension-runtime.js +1 -1
  207. package/dist/client/extensions/agent-native-extension-runtime.js.map +1 -1
  208. package/dist/client/navigation/index.d.ts +1 -1
  209. package/dist/client/navigation/index.d.ts.map +1 -1
  210. package/dist/client/navigation/index.js +1 -1
  211. package/dist/client/navigation/index.js.map +1 -1
  212. package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
  213. package/dist/client/org/OrgSwitcher.js +9 -13
  214. package/dist/client/org/OrgSwitcher.js.map +1 -1
  215. package/dist/client/settings/ExtensionsSettingsContent.js +1 -1
  216. package/dist/client/settings/ExtensionsSettingsContent.js.map +1 -1
  217. package/dist/collab/awareness.d.ts +2 -2
  218. package/dist/collab/awareness.d.ts.map +1 -1
  219. package/dist/collab/struct-routes.d.ts +1 -1
  220. package/dist/extensions/theme.js +1 -1
  221. package/dist/extensions/theme.js.map +1 -1
  222. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  223. package/dist/localization/default-messages.d.ts +2 -0
  224. package/dist/localization/default-messages.d.ts.map +1 -1
  225. package/dist/localization/default-messages.js +2 -0
  226. package/dist/localization/default-messages.js.map +1 -1
  227. package/dist/provider-api/actions/provider-api.d.ts +2 -2
  228. package/dist/secrets/routes.d.ts +9 -9
  229. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  230. package/dist/server/core-routes-plugin.js +8 -1
  231. package/dist/server/core-routes-plugin.js.map +1 -1
  232. package/dist/server/framework-request-handler.d.ts.map +1 -1
  233. package/dist/server/framework-request-handler.js +17 -27
  234. package/dist/server/framework-request-handler.js.map +1 -1
  235. package/dist/server/realtime-token.d.ts +1 -1
  236. package/dist/styles/agent-native.css +13 -0
  237. package/dist/templates/chat/app/components/layout/Layout.tsx +3 -0
  238. package/dist/templates/chat/app/components/layout/Sidebar.tsx +78 -45
  239. package/dist/templates/chat/app/global.css +1 -1
  240. package/dist/templates/chat/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  241. package/dist/templates/chat/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  242. package/dist/templates/default/app/global.css +1 -1
  243. package/dist/tracking/error-capture.d.ts +14 -0
  244. package/dist/tracking/error-capture.d.ts.map +1 -0
  245. package/dist/tracking/error-capture.js +113 -0
  246. package/dist/tracking/error-capture.js.map +1 -0
  247. package/dist/tracking/index.d.ts +1 -0
  248. package/dist/tracking/index.d.ts.map +1 -1
  249. package/dist/tracking/index.js +1 -0
  250. package/dist/tracking/index.js.map +1 -1
  251. package/package.json +2 -2
  252. package/src/cli/context-xray-local.ts +1 -1
  253. package/src/cli/index.ts +63 -18
  254. package/src/cli/skills.ts +5 -0
  255. package/src/cli/telemetry.ts +118 -1
  256. package/src/client/AgentPanel.tsx +10 -0
  257. package/src/client/CommandMenu.tsx +13 -1
  258. package/src/client/agent-page/AgentTabsPage.tsx +39 -4
  259. package/src/client/analytics.ts +13 -0
  260. package/src/client/error-capture.ts +6 -1
  261. package/src/client/extensions/ExtensionsListPage.tsx +12 -5
  262. package/src/client/extensions/agent-native-extension-runtime.ts +1 -1
  263. package/src/client/navigation/index.ts +2 -0
  264. package/src/client/org/OrgSwitcher.tsx +14 -32
  265. package/src/client/settings/ExtensionsSettingsContent.tsx +1 -1
  266. package/src/extensions/theme.ts +1 -1
  267. package/src/localization/default-messages.ts +2 -0
  268. package/src/server/core-routes-plugin.ts +10 -1
  269. package/src/server/framework-request-handler.ts +17 -26
  270. package/src/styles/agent-native.css +13 -0
  271. package/src/templates/chat/app/components/layout/Layout.tsx +3 -0
  272. package/src/templates/chat/app/components/layout/Sidebar.tsx +78 -45
  273. package/src/templates/chat/app/global.css +1 -1
  274. package/src/templates/chat/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  275. package/src/templates/chat/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  276. package/src/templates/default/app/global.css +1 -1
  277. package/src/tracking/error-capture.ts +151 -0
  278. package/src/tracking/index.ts +5 -0
@@ -35,7 +35,7 @@
35
35
  --accent-foreground: 0 0% 98%;
36
36
 
37
37
  /* Destructive - bright enough for text on dark surfaces */
38
- --destructive: 0 84.2% 60.2%;
38
+ --destructive: 0 91% 71%;
39
39
  --destructive-foreground: 0 0% 98%;
40
40
 
41
41
  /* Borders - Subtle and thin */
@@ -139,13 +139,13 @@
139
139
  }
140
140
 
141
141
  .dashboard-panel-skeleton {
142
- background-color: hsl(var(--muted-foreground) / 0.24);
142
+ background-color: hsl(var(--muted-foreground) / 0.18);
143
143
  background-image: linear-gradient(
144
144
  105deg,
145
145
  transparent 24%,
146
- hsl(var(--foreground) / 0.06) 42%,
147
- hsl(var(--foreground) / 0.16) 50%,
148
- hsl(var(--foreground) / 0.06) 58%,
146
+ hsl(var(--foreground) / 0.04) 42%,
147
+ hsl(var(--foreground) / 0.1) 50%,
148
+ hsl(var(--foreground) / 0.04) 58%,
149
149
  transparent 76%
150
150
  );
151
151
  background-size: 220% 100%;
@@ -0,0 +1,42 @@
1
+ import { EMBED_TOKEN_QUERY_PARAM } from "@agent-native/core/shared";
2
+
3
+ export const DASHBOARD_REPORT_BOOTSTRAP_TIMEOUT_MS = 12_000;
4
+ export const DASHBOARD_REPORT_BOOTSTRAP_RETRY_DELAY_MS = 500;
5
+ export const DASHBOARD_REPORT_CAPTURE_ERROR_LIMIT = 240;
6
+
7
+ export type DashboardReportCapturePhase =
8
+ | "loading"
9
+ | "error"
10
+ | "missing"
11
+ | "ready";
12
+
13
+ export function isDashboardReportScreenshot(search: string): boolean {
14
+ return new URLSearchParams(search).get("reportScreenshot") === "1";
15
+ }
16
+
17
+ /**
18
+ * The server verifies this scoped token on every action. This only prevents
19
+ * the client session gate from redirecting an otherwise authorized capture.
20
+ */
21
+ export function hasDashboardReportEmbedToken(
22
+ search: string,
23
+ storedEmbedToken?: string | null,
24
+ ): boolean {
25
+ if (!isDashboardReportScreenshot(search)) return false;
26
+ return Boolean(
27
+ new URLSearchParams(search).get(EMBED_TOKEN_QUERY_PARAM)?.trim() ||
28
+ storedEmbedToken?.trim(),
29
+ );
30
+ }
31
+
32
+ export function dashboardReportCaptureError(error: unknown): string {
33
+ const message = error instanceof Error ? error.message : String(error);
34
+ return message
35
+ .replace(
36
+ new RegExp(`(${EMBED_TOKEN_QUERY_PARAM}=)[^&\\s]+`, "g"),
37
+ "$1[REDACTED]",
38
+ )
39
+ .replace(/\s+/g, " ")
40
+ .trim()
41
+ .slice(0, DASHBOARD_REPORT_CAPTURE_ERROR_LIMIT);
42
+ }
@@ -80,7 +80,7 @@ export function KpiChart({
80
80
  });
81
81
 
82
82
  return (
83
- <Card className="bg-card border-border/50">
83
+ <Card className="bg-card">
84
84
  <CardHeader className="pb-2">
85
85
  <div className="flex items-start justify-between gap-2">
86
86
  <div className="flex-1">
@@ -33,7 +33,7 @@ export function ChartTypePicker({ value, onChange }: ChartTypePickerProps) {
33
33
  onValueChange={(v) => {
34
34
  if (v) onChange(v as ChartType);
35
35
  }}
36
- className="border rounded-md p-0.5"
36
+ className="rounded-md bg-card p-0.5"
37
37
  >
38
38
  {CHART_TYPES.map((ct) => (
39
39
  <ToggleGroupItem
@@ -17,7 +17,7 @@ interface DateRangePickerProps {
17
17
 
18
18
  export function DateRangePicker({ value, onChange }: DateRangePickerProps) {
19
19
  return (
20
- <div className="flex items-center border rounded-md p-0.5 gap-0.5">
20
+ <div className="flex items-center gap-0.5 rounded-md bg-card p-0.5">
21
21
  {OPTIONS.map((opt) => (
22
22
  <Button
23
23
  key={opt.value}
@@ -15,7 +15,7 @@ interface EventRowProps {
15
15
 
16
16
  export function EventRow({ event, onChange, onRemove }: EventRowProps) {
17
17
  return (
18
- <div className="border rounded-lg p-3 space-y-2 bg-card">
18
+ <div className="space-y-2 rounded-lg bg-card p-3">
19
19
  <div className="flex items-center gap-2">
20
20
  <IconGripVertical className="h-4 w-4 text-muted-foreground shrink-0 cursor-grab" />
21
21
  <div className="flex-1 min-w-0">
@@ -23,7 +23,7 @@ export function SqlPreview({ sql }: SqlPreviewProps) {
23
23
  };
24
24
 
25
25
  return (
26
- <div className="border rounded-lg">
26
+ <div className="rounded-lg bg-card">
27
27
  <button
28
28
  className="flex items-center gap-2 w-full px-3 py-2 text-sm text-muted-foreground hover:text-foreground transition-colors"
29
29
  type="button"
@@ -51,7 +51,7 @@ export function SqlPreview({ sql }: SqlPreviewProps) {
51
51
  )}
52
52
  >
53
53
  <div className="min-h-0 overflow-hidden">
54
- <div className="relative border-t">
54
+ <div className="relative">
55
55
  <SqlHighlight
56
56
  sql={sql}
57
57
  preClassName="p-3 overflow-auto max-h-[300px] bg-muted/50 rounded-b-lg"
@@ -256,7 +256,7 @@ export function DashboardFilterBar({
256
256
  <Collapsible
257
257
  open={filtersOpen}
258
258
  onOpenChange={setFiltersOpen}
259
- className="group rounded-lg border border-border bg-card px-3 py-2"
259
+ className="group rounded-lg bg-card px-3 py-2"
260
260
  >
261
261
  <div className="flex flex-wrap items-end justify-between gap-3">
262
262
  <CollapsibleContent className="min-w-0 flex-1">
@@ -426,8 +426,8 @@ function FilterControl({
426
426
  value={current}
427
427
  onValueChange={(v) => setValue({ [filter.id]: v })}
428
428
  >
429
- <SelectTrigger className="h-8 w-[140px] text-xs">
430
- <SelectValue className="flex-1 text-left" />
429
+ <SelectTrigger className="h-8 w-[140px] justify-start gap-2 text-xs">
430
+ <SelectValue className="min-w-0 flex-1 text-left" />
431
431
  </SelectTrigger>
432
432
  <SelectContent>
433
433
  {filter.options?.map((opt) => (
@@ -294,7 +294,7 @@ export function EmailReportDialog({
294
294
  <button
295
295
  key={sub.id}
296
296
  type="button"
297
- className="flex w-full items-center justify-between gap-3 rounded-md border px-3 py-2 text-left transition-colors hover:bg-muted/60 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
297
+ className="flex w-full items-center justify-between gap-3 rounded-md bg-card px-3 py-2 text-left transition-colors hover:bg-muted/60 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
298
298
  onClick={() => loadSubscription(sub)}
299
299
  >
300
300
  <span className="min-w-0">
@@ -383,7 +383,7 @@ export function EmailReportDialog({
383
383
  />
384
384
  </div>
385
385
 
386
- <div className="flex items-center justify-between gap-3 rounded-md border px-3 py-2 sm:col-span-2">
386
+ <div className="flex items-center justify-between gap-3 rounded-md bg-card px-3 py-2 sm:col-span-2">
387
387
  <div className="min-w-0">
388
388
  <Label>{t("sqlDashboard.reportEnabled")}</Label>
389
389
  <p className="text-xs text-muted-foreground">
@@ -506,7 +506,7 @@ function PanelEditorContent({
506
506
  </div>
507
507
 
508
508
  {isExtensionPanel ? (
509
- <div className="grid gap-4 rounded-lg border p-4">
509
+ <div className="grid gap-4 rounded-lg bg-card p-4">
510
510
  <div className="grid gap-1.5">
511
511
  <Label htmlFor="panel-extension-mode">
512
512
  {t("panelEditor.extensionDisplay")}
@@ -371,7 +371,7 @@ export function SqlChartCard({
371
371
  data-dashboard-report-panel-id={panel.id}
372
372
  data-dashboard-report-panel-title={panel.title}
373
373
  className={cn(
374
- "dashboard-extension-card group relative h-full rounded-lg border border-transparent transition-colors",
374
+ "dashboard-extension-card group relative h-full rounded-lg transition-colors",
375
375
  selectedForChat && "border-foreground/35 ring-1 ring-foreground/10",
376
376
  )}
377
377
  >
@@ -11,6 +11,7 @@ import {
11
11
  callAction,
12
12
  useChangeVersions,
13
13
  useActionMutation,
14
+ type AuthSession,
14
15
  } from "@agent-native/core/client/hooks";
15
16
  import { useT } from "@agent-native/core/client/i18n";
16
17
  import { ShareButton } from "@agent-native/core/client/sharing";
@@ -104,6 +105,12 @@ import {
104
105
  } from "@/hooks/use-dashboard-chat-context";
105
106
  import { useDashboardViews } from "@/hooks/use-dashboard-views";
106
107
  import { useUserPref } from "@/hooks/use-user-pref";
108
+ import {
109
+ DASHBOARD_REPORT_BOOTSTRAP_RETRY_DELAY_MS,
110
+ DASHBOARD_REPORT_BOOTSTRAP_TIMEOUT_MS,
111
+ dashboardReportCaptureError,
112
+ type DashboardReportCapturePhase,
113
+ } from "@/lib/dashboard-report-capture";
107
114
  import { incrementItemView } from "@/lib/item-popularity";
108
115
  import {
109
116
  sqlDashboardPrefetchKey,
@@ -423,14 +430,31 @@ function parseDashboardCatalogMetadata(
423
430
  };
424
431
  }
425
432
 
426
- async function fetchDashboard(id: string): Promise<FetchedDashboard | null> {
433
+ async function fetchDashboard(
434
+ id: string,
435
+ options?: { reportScreenshot?: boolean },
436
+ ): Promise<FetchedDashboard | null> {
427
437
  try {
428
438
  const data: any = await callAction(
429
439
  "get-sql-dashboard",
430
440
  { id, includeConfig: true },
431
- { method: "GET" },
441
+ {
442
+ method: "GET",
443
+ ...(options?.reportScreenshot
444
+ ? { timeoutMs: DASHBOARD_REPORT_BOOTSTRAP_TIMEOUT_MS }
445
+ : {}),
446
+ },
432
447
  );
433
- if (!data || data.error) return null;
448
+ if (!data) return null;
449
+ if (data.error) {
450
+ throw new Error(
451
+ typeof data.message === "string" && data.message
452
+ ? data.message
453
+ : typeof data.error === "string"
454
+ ? data.error
455
+ : "Dashboard bootstrap failed",
456
+ );
457
+ }
434
458
  return {
435
459
  id,
436
460
  config: {
@@ -463,11 +487,44 @@ async function fetchDashboard(id: string): Promise<FetchedDashboard | null> {
463
487
  canManage:
464
488
  typeof data.canManage === "boolean" ? data.canManage : undefined,
465
489
  };
466
- } catch {
490
+ } catch (error) {
491
+ if (options?.reportScreenshot) throw error;
467
492
  return null;
468
493
  }
469
494
  }
470
495
 
496
+ function DashboardReportCaptureSurface({
497
+ phase,
498
+ panelIds,
499
+ error,
500
+ className,
501
+ children,
502
+ }: {
503
+ phase: DashboardReportCapturePhase;
504
+ panelIds?: string[];
505
+ error?: unknown;
506
+ className?: string;
507
+ children: React.ReactNode;
508
+ }) {
509
+ const captureError = error ? dashboardReportCaptureError(error) : undefined;
510
+
511
+ return (
512
+ <div
513
+ className={className}
514
+ data-dashboard-report-capture
515
+ data-dashboard-report-ready={phase === "ready" ? "true" : "false"}
516
+ data-dashboard-report-phase={phase}
517
+ data-dashboard-report-fetch-state={phase}
518
+ data-dashboard-report-error={captureError || undefined}
519
+ data-dashboard-report-panel-ids={
520
+ panelIds ? JSON.stringify(panelIds) : undefined
521
+ }
522
+ >
523
+ {children}
524
+ </div>
525
+ );
526
+ }
527
+
471
528
  /**
472
529
  * Save dashboard config via the update-dashboard action. Throws on error so
473
530
  * callers (e.g. the panel editor dialog) can surface BigQuery validation
@@ -484,13 +541,34 @@ async function saveDashboard(
484
541
  }
485
542
 
486
543
  export default function SqlDashboardPage() {
544
+ const [searchParams] = useSearchParams();
545
+
546
+ if (searchParams.get("reportScreenshot") === "1") {
547
+ return <SqlDashboardPageContent reportScreenshot session={null} />;
548
+ }
549
+
550
+ return <InteractiveSqlDashboardPage />;
551
+ }
552
+
553
+ function InteractiveSqlDashboardPage() {
554
+ const { session } = useSession();
555
+
556
+ return <SqlDashboardPageContent reportScreenshot={false} session={session} />;
557
+ }
558
+
559
+ function SqlDashboardPageContent({
560
+ reportScreenshot,
561
+ session,
562
+ }: {
563
+ reportScreenshot: boolean;
564
+ session: AuthSession | null;
565
+ }) {
487
566
  const t = useT();
488
567
  const [searchParams, setSearchParams] = useSearchParams();
489
568
  const { id: routeId } = useParams<{ id: string }>();
490
569
  const queryClient = useQueryClient();
491
570
  const navigate = useNavigate();
492
571
  const dashboardId = searchParams.get("id") || routeId;
493
- const reportScreenshot = searchParams.get("reportScreenshot") === "1";
494
572
  const reportSettingsRequested = searchParams.get("reportSettings") === "1";
495
573
  const reportPanelWindow = reportScreenshot
496
574
  ? parseReportPanelWindow(
@@ -573,8 +651,12 @@ export default function SqlDashboardPage() {
573
651
  enabled: !!dashboardId,
574
652
  queryFn: async () => {
575
653
  if (!dashboardId) return null;
576
- return fetchDashboard(dashboardId);
654
+ return fetchDashboard(dashboardId, { reportScreenshot });
577
655
  },
656
+ retry: reportScreenshot ? 1 : false,
657
+ retryDelay: reportScreenshot
658
+ ? DASHBOARD_REPORT_BOOTSTRAP_RETRY_DELAY_MS
659
+ : undefined,
578
660
  staleTime: 30_000,
579
661
  placeholderData: (prev) => prev,
580
662
  initialData: () => {
@@ -602,7 +684,6 @@ export default function SqlDashboardPage() {
602
684
  const [editingPanel, setEditingPanel] = useState<SqlPanel | null>(null);
603
685
 
604
686
  // ── Collaborative editing ──────────────────────────────────────────
605
- const { session } = useSession();
606
687
  const currentUser: CollabUser | undefined =
607
688
  !reportScreenshot && session?.email
608
689
  ? {
@@ -1516,41 +1597,6 @@ export default function SqlDashboardPage() {
1516
1597
  <TooltipContent>{t("sqlDashboard.details")}</TooltipContent>
1517
1598
  </Tooltip>
1518
1599
  <DropdownMenuContent align="end" className="w-72">
1519
- <DropdownMenuLabel className="font-normal">
1520
- <DashboardMetadata
1521
- createdAt={dashboardCreatedAt}
1522
- createdBy={dashboardOwner}
1523
- updatedAt={dashboardUpdatedAt}
1524
- updatedBy={dashboardUpdatedBy}
1525
- />
1526
- <div className="mt-2 flex flex-col gap-1.5 text-xs text-muted-foreground">
1527
- {dashboardVisibility ? (
1528
- <span className="flex items-center gap-1.5">
1529
- {dashboardVisibility === "public" ? (
1530
- <IconWorld className="h-3 w-3" />
1531
- ) : dashboardVisibility === "org" ? (
1532
- <IconUsersGroup className="h-3 w-3" />
1533
- ) : (
1534
- <IconLock className="h-3 w-3" />
1535
- )}
1536
- {dashboardVisibility === "public"
1537
- ? t("sqlDashboard.public")
1538
- : dashboardVisibility === "org"
1539
- ? t("sqlDashboard.sharedWithOrg")
1540
- : t("sqlDashboard.private")}
1541
- </span>
1542
- ) : null}
1543
- {hiddenAt && (
1544
- <span className="flex items-center gap-1.5 font-medium text-amber-600 dark:text-amber-400">
1545
- <IconEyeOff className="h-3 w-3" />
1546
- {t("sqlDashboard.hidden")}
1547
- </span>
1548
- )}
1549
- </div>
1550
- </DropdownMenuLabel>
1551
- {(canEdit && !archivedAt) || canManage ? (
1552
- <DropdownMenuSeparator />
1553
- ) : null}
1554
1600
  {dashboardId && canEdit && !archivedAt ? (
1555
1601
  <DropdownMenuItem
1556
1602
  onSelect={(event) => {
@@ -1616,6 +1662,41 @@ export default function SqlDashboardPage() {
1616
1662
  {t("sqlDashboard.deletePermanently")}
1617
1663
  </DropdownMenuItem>
1618
1664
  ) : null}
1665
+ {dashboardId || (canEdit && !archivedAt) || canManage ? (
1666
+ <DropdownMenuSeparator />
1667
+ ) : null}
1668
+ <DropdownMenuLabel className="font-normal">
1669
+ <DashboardMetadata
1670
+ createdAt={dashboardCreatedAt}
1671
+ createdBy={dashboardOwner}
1672
+ updatedAt={dashboardUpdatedAt}
1673
+ updatedBy={dashboardUpdatedBy}
1674
+ />
1675
+ <div className="mt-2 flex flex-col gap-1.5 text-xs text-muted-foreground">
1676
+ {dashboardVisibility ? (
1677
+ <span className="flex items-center gap-1.5">
1678
+ {dashboardVisibility === "public" ? (
1679
+ <IconWorld className="h-3 w-3" />
1680
+ ) : dashboardVisibility === "org" ? (
1681
+ <IconUsersGroup className="h-3 w-3" />
1682
+ ) : (
1683
+ <IconLock className="h-3 w-3" />
1684
+ )}
1685
+ {dashboardVisibility === "public"
1686
+ ? t("sqlDashboard.public")
1687
+ : dashboardVisibility === "org"
1688
+ ? t("sqlDashboard.sharedWithOrg")
1689
+ : t("sqlDashboard.private")}
1690
+ </span>
1691
+ ) : null}
1692
+ {hiddenAt && (
1693
+ <span className="flex items-center gap-1.5 font-medium text-amber-600 dark:text-amber-400">
1694
+ <IconEyeOff className="h-3 w-3" />
1695
+ {t("sqlDashboard.hidden")}
1696
+ </span>
1697
+ )}
1698
+ </div>
1699
+ </DropdownMenuLabel>
1619
1700
  </DropdownMenuContent>
1620
1701
  </DropdownMenu>
1621
1702
  {dashboardId ? (
@@ -1687,6 +1768,15 @@ export default function SqlDashboardPage() {
1687
1768
  );
1688
1769
 
1689
1770
  if (!dashboardId) {
1771
+ if (reportScreenshot) {
1772
+ return (
1773
+ <DashboardReportCaptureSurface phase="missing">
1774
+ <div className="flex h-64 items-center justify-center text-muted-foreground">
1775
+ {t("sqlDashboard.noDashboardSelected")}
1776
+ </div>
1777
+ </DashboardReportCaptureSurface>
1778
+ );
1779
+ }
1690
1780
  return (
1691
1781
  <div className="flex items-center justify-center h-64 text-muted-foreground">
1692
1782
  {t("sqlDashboard.noDashboardSelected")}
@@ -1694,21 +1784,42 @@ export default function SqlDashboardPage() {
1694
1784
  );
1695
1785
  }
1696
1786
 
1787
+ if (reportScreenshot && dashboardQuery.isError) {
1788
+ return (
1789
+ <DashboardReportCaptureSurface phase="error" error={dashboardQuery.error}>
1790
+ <DashboardSkeleton />
1791
+ </DashboardReportCaptureSurface>
1792
+ );
1793
+ }
1794
+
1697
1795
  if (!loaded) {
1796
+ if (reportScreenshot) {
1797
+ return (
1798
+ <DashboardReportCaptureSurface phase="loading">
1799
+ <DashboardSkeleton />
1800
+ </DashboardReportCaptureSurface>
1801
+ );
1802
+ }
1698
1803
  return <DashboardSkeleton />;
1699
1804
  }
1700
1805
 
1701
- if (!dashboard) return <BlankDashboard />;
1806
+ if (!dashboard) {
1807
+ if (reportScreenshot) {
1808
+ return (
1809
+ <DashboardReportCaptureSurface phase="missing">
1810
+ <BlankDashboard />
1811
+ </DashboardReportCaptureSurface>
1812
+ );
1813
+ }
1814
+ return <BlankDashboard />;
1815
+ }
1702
1816
 
1703
1817
  return (
1704
- <div
1818
+ <DashboardReportCaptureSurface
1705
1819
  className="space-y-4"
1706
- data-dashboard-report-capture
1707
- data-dashboard-report-ready={loaded && dashboard ? "true" : "false"}
1708
- data-dashboard-report-panel-ids={
1709
- reportScreenshot
1710
- ? JSON.stringify(listReportablePanelIds(visiblePanels))
1711
- : undefined
1820
+ phase="ready"
1821
+ panelIds={
1822
+ reportScreenshot ? listReportablePanelIds(visiblePanels) : undefined
1712
1823
  }
1713
1824
  >
1714
1825
  {hiddenAt ? (
@@ -2031,6 +2142,6 @@ export default function SqlDashboardPage() {
2031
2142
  existingPanelTitles={dashboard.panels.map((p) => p.title)}
2032
2143
  />
2033
2144
  ) : null}
2034
- </div>
2145
+ </DashboardReportCaptureSurface>
2035
2146
  );
2036
2147
  }
@@ -6,6 +6,7 @@ import {
6
6
  createAgentNativeQueryClient,
7
7
  useDbSync,
8
8
  } from "@agent-native/core/client/hooks";
9
+ import { getEmbedAuthToken } from "@agent-native/core/client/host";
9
10
  import { getLocaleInitScript } from "@agent-native/core/client/i18n";
10
11
  import { getThemeInitScript } from "@agent-native/core/client/ui";
11
12
  import { useQueryClient } from "@tanstack/react-query";
@@ -31,6 +32,10 @@ import { TAB_ID } from "@/lib/tab-id";
31
32
  import { CommandPalette } from "./components/layout/CommandPalette";
32
33
  import { Layout as AppLayout } from "./components/layout/Layout";
33
34
  import { i18nCatalog } from "./i18n";
35
+ import {
36
+ hasDashboardReportEmbedToken,
37
+ isDashboardReportScreenshot,
38
+ } from "./lib/dashboard-report-capture";
34
39
 
35
40
  import stylesheet from "./global.css?url";
36
41
  configureTracking({
@@ -146,6 +151,11 @@ export default function Root() {
146
151
  // server/plugins/auth.ts.
147
152
  const isPublicStatusPath =
148
153
  location.pathname === "/status" || location.pathname.startsWith("/status/");
154
+ const isDashboardReportCapture = isDashboardReportScreenshot(location.search);
155
+ const hasReportEmbedToken = hasDashboardReportEmbedToken(
156
+ location.search,
157
+ getEmbedAuthToken(),
158
+ );
149
159
 
150
160
  if (isPublicStatusPath) {
151
161
  return (
@@ -163,6 +173,24 @@ export default function Root() {
163
173
  );
164
174
  }
165
175
 
176
+ if (isDashboardReportCapture && hasReportEmbedToken) {
177
+ return (
178
+ <AppToolkitProvider>
179
+ <AppProviders
180
+ queryClient={queryClient}
181
+ sessionBypass
182
+ defaultTheme="dark"
183
+ toaster={null}
184
+ i18n={{ catalog: i18nCatalog }}
185
+ >
186
+ <AppLayout>
187
+ <Outlet />
188
+ </AppLayout>
189
+ </AppProviders>
190
+ </AppToolkitProvider>
191
+ );
192
+ }
193
+
166
194
  return (
167
195
  // defaultTheme="dark": analytics defaults to dark mode if no stored preference.
168
196
  // toaster={null}: suppress AppProviders' built-in sonner; analytics renders
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-07-24
4
+ ---
5
+
6
+ Analytics charts now explain slow loads and offer a direct retry action.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-07-24
4
+ ---
5
+
6
+ Secondary controls and dashboard surfaces now use quieter borderless styling.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-24
4
+ ---
5
+
6
+ Daily dashboard emails now load signed reports more reliably instead of falling back to a link-only message
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-07-24
4
+ ---
5
+
6
+ Manage agent is clearly marked as a link to its dedicated page
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-07-24
4
+ ---
5
+
6
+ Sidebar utility controls now follow a consistent footer order.
@@ -75,7 +75,7 @@
75
75
  "chartType": "area",
76
76
  "source": "first-party",
77
77
  "width": 2,
78
- "sql": "WITH offsets AS (SELECT (ROW_NUMBER() OVER (ORDER BY event_date) - 1)::int AS n FROM analytics_events LIMIT 800), signup_events AS (SELECT event_date AS date, COALESCE(NULLIF(template, ''), NULLIF(properties::jsonb ->> 'templateId', ''), NULLIF(properties::jsonb ->> 'agent_native_template', ''), NULLIF(properties::jsonb ->> 'agentNativeTemplate', ''), NULLIF(app, ''), NULLIF(properties::jsonb ->> 'agent_native_app', ''), NULLIF(properties::jsonb ->> 'agentNativeApp', ''), 'unknown') AS template FROM analytics_events WHERE event_name = 'signup' AND ('{{timeRange}}' IN ('', 'all') OR ('{{timeRange}}' = '7d' AND event_date >= to_char(CURRENT_DATE - INTERVAL '7 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '30d' AND event_date >= to_char(CURRENT_DATE - INTERVAL '30 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '90d' AND event_date >= to_char(CURRENT_DATE - INTERVAL '90 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '180d' AND event_date >= to_char(CURRENT_DATE - INTERVAL '180 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '365d' AND event_date >= to_char(CURRENT_DATE - INTERVAL '365 days', 'YYYY-MM-DD'))) AND ('{{emailFilter}}' IN ('', 'all') OR ('{{emailFilter}}' = 'exclude_builder' AND lower(coalesce(user_id, '')) NOT LIKE '%@builder.io') OR ('{{emailFilter}}' = 'only_builder' AND lower(coalesce(user_id, '')) LIKE '%@builder.io'))), bounds AS (SELECT MIN(date::date) AS start_date, MAX(date::date) AS end_date FROM signup_events), dates AS (SELECT to_char(bounds.start_date + offsets.n, 'YYYY-MM-DD') AS date FROM bounds CROSS JOIN offsets WHERE bounds.start_date IS NOT NULL AND bounds.start_date + offsets.n <= bounds.end_date), templates AS (SELECT DISTINCT template FROM signup_events), daily AS (SELECT date, template, COUNT(*) AS count FROM signup_events GROUP BY date, template) SELECT dates.date, templates.template, COALESCE(daily.count, 0) AS count FROM dates CROSS JOIN templates LEFT JOIN daily ON daily.date = dates.date AND daily.template = templates.template ORDER BY dates.date, templates.template",
78
+ "sql": "WITH digits AS (SELECT 0 AS n UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9), offsets AS (SELECT ones.n + tens.n * 10 + hundreds.n * 100 AS n FROM digits ones CROSS JOIN digits tens CROSS JOIN digits hundreds WHERE hundreds.n < 8), signup_events AS (SELECT event_date AS date, COALESCE(NULLIF(template, ''), NULLIF(properties::jsonb ->> 'templateId', ''), NULLIF(properties::jsonb ->> 'agent_native_template', ''), NULLIF(properties::jsonb ->> 'agentNativeTemplate', ''), NULLIF(app, ''), NULLIF(properties::jsonb ->> 'agent_native_app', ''), NULLIF(properties::jsonb ->> 'agentNativeApp', ''), 'unknown') AS template FROM analytics_events WHERE event_name = 'signup' AND (event_date <= to_char(CURRENT_DATE, 'YYYY-MM-DD') AND ('{{timeRange}}' IN ('', 'all') OR ('{{timeRange}}' = '7d' AND event_date >= to_char(CURRENT_DATE - INTERVAL '7 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '30d' AND event_date >= to_char(CURRENT_DATE - INTERVAL '30 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '90d' AND event_date >= to_char(CURRENT_DATE - INTERVAL '90 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '180d' AND event_date >= to_char(CURRENT_DATE - INTERVAL '180 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '365d' AND event_date >= to_char(CURRENT_DATE - INTERVAL '365 days', 'YYYY-MM-DD')))) AND ('{{emailFilter}}' IN ('', 'all') OR ('{{emailFilter}}' = 'exclude_builder' AND lower(coalesce(user_id, '')) NOT LIKE '%@builder.io') OR ('{{emailFilter}}' = 'only_builder' AND lower(coalesce(user_id, '')) LIKE '%@builder.io'))), bounds AS (SELECT MIN(date::date) AS start_date, MAX(date::date) AS end_date FROM signup_events), dates AS (SELECT to_char(bounds.start_date + offsets.n, 'YYYY-MM-DD') AS date FROM bounds CROSS JOIN offsets WHERE bounds.start_date IS NOT NULL AND bounds.start_date + offsets.n <= bounds.end_date), templates AS (SELECT DISTINCT template FROM signup_events), daily AS (SELECT date, template, COUNT(*) AS count FROM signup_events GROUP BY date, template) SELECT dates.date, templates.template, COALESCE(daily.count, 0) AS count FROM dates CROSS JOIN templates LEFT JOIN daily ON daily.date = dates.date AND daily.template = templates.template ORDER BY dates.date, templates.template",
79
79
  "config": {
80
80
  "xKey": "date",
81
81
  "yKey": "count",
@@ -113,6 +113,11 @@ export const dashboardReportSubscriptions = table(
113
113
  enum: ["success", "error", "running"],
114
114
  }),
115
115
  lastError: text("last_error"),
116
+ lastCaptureAt: text("last_capture_at"),
117
+ lastCaptureMode: text("last_capture_mode", {
118
+ enum: ["full", "partial", "none"],
119
+ }),
120
+ lastCaptureError: text("last_capture_error"),
116
121
  createdAt: text("created_at").notNull().default(now()),
117
122
  updatedAt: text("updated_at").notNull().default(now()),
118
123
  ownerEmail: text("owner_email").notNull().default("local@localhost"),