@agent-native/core 0.78.8 → 0.79.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/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +25 -0
  3. package/corpus/core/docs/content/actions.md +4 -2
  4. package/corpus/core/docs/content/agent-surfaces.md +9 -0
  5. package/corpus/core/docs/content/extensions.md +10 -0
  6. package/corpus/core/docs/content/generative-ui.md +217 -0
  7. package/corpus/core/docs/content/key-concepts.md +2 -2
  8. package/corpus/core/docs/content/mcp-apps.md +3 -5
  9. package/corpus/core/docs/content/native-chat-ui.md +9 -5
  10. package/corpus/core/docs/content/tracking.md +9 -3
  11. package/corpus/core/package.json +1 -1
  12. package/corpus/core/src/action-ui.ts +1 -0
  13. package/corpus/core/src/client/analytics.ts +195 -12
  14. package/corpus/core/src/client/chat/index.ts +1 -0
  15. package/corpus/core/src/client/chat/tool-call-display.tsx +5 -2
  16. package/corpus/core/src/client/chat/widgets/InlineExtensionWidget.tsx +139 -0
  17. package/corpus/core/src/client/chat/widgets/builtin-tool-renderers.tsx +27 -1
  18. package/corpus/core/src/client/conversation/AgentConversation.tsx +38 -0
  19. package/corpus/core/src/client/conversation/code-agent-transcript.ts +9 -0
  20. package/corpus/core/src/client/conversation/types.ts +4 -0
  21. package/corpus/core/src/client/extensions/EmbeddedExtension.tsx +27 -5
  22. package/corpus/core/src/client/extensions/ExtensionViewer.tsx +26 -5
  23. package/corpus/core/src/client/extensions/InlineExtensionFrame.tsx +654 -0
  24. package/corpus/core/src/client/extensions/iframe-bridge.ts +30 -0
  25. package/corpus/core/src/client/extensions/index.ts +5 -0
  26. package/corpus/core/src/client/index.ts +1 -0
  27. package/corpus/core/src/client/session-replay.ts +89 -14
  28. package/corpus/core/src/code-agents/transcript-normalizer.ts +14 -0
  29. package/corpus/core/src/extensions/actions.ts +218 -1
  30. package/corpus/core/src/extensions/html-shell.ts +70 -3
  31. package/corpus/core/src/extensions/routes.ts +12 -4
  32. package/corpus/core/src/index.browser.ts +1 -0
  33. package/corpus/core/src/index.ts +1 -0
  34. package/corpus/core/src/mcp/build-server.ts +1 -1
  35. package/corpus/core/src/mcp/embed-app.ts +11 -1
  36. package/corpus/core/src/server/agent-chat-plugin.ts +21 -9
  37. package/corpus/core/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +13 -0
  38. package/corpus/core/src/templates/workspace-core/.agents/skills/extensions/references/api.md +2 -0
  39. package/corpus/core/src/templates/workspace-core/.agents/skills/generative-ui/SKILL.md +115 -0
  40. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +198 -59
  41. package/corpus/templates/analytics/AGENTS.md +12 -0
  42. package/corpus/templates/analytics/actions/dashboard-mutation-api.ts +1105 -0
  43. package/corpus/templates/analytics/actions/dashboard-panel-order.ts +169 -0
  44. package/corpus/templates/analytics/actions/get-sql-dashboard.ts +89 -6
  45. package/corpus/templates/analytics/actions/mutate-dashboard.ts +333 -0
  46. package/corpus/templates/analytics/actions/reorder-dashboard-panels.ts +214 -0
  47. package/corpus/templates/analytics/actions/send-dashboard-report-now.ts +48 -21
  48. package/corpus/templates/analytics/actions/update-dashboard.ts +193 -100
  49. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +11 -0
  50. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +1 -1
  51. package/corpus/templates/analytics/app/global.css +81 -10
  52. package/corpus/templates/analytics/app/i18n-data.ts +249 -4
  53. package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/ChartCard.tsx +3 -3
  54. package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/index.tsx +41 -1
  55. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/EmailReportDialog.tsx +1 -1
  56. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +4 -4
  57. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +48 -18
  58. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/dashboard-layout.ts +32 -0
  59. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +204 -70
  60. package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +1101 -227
  61. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +160 -133
  62. package/corpus/templates/analytics/changelog/2026-06-26-agents-can-now-edit-dashboards-through-a-typed-mutation-scri.md +6 -0
  63. package/corpus/templates/analytics/changelog/2026-06-26-dashboard-bar-chart-hovers-stay-subtle-in-dark-mode.md +6 -0
  64. package/corpus/templates/analytics/changelog/2026-06-26-dashboard-chart-moves-are-now-handled-by-panel-id-making-sim.md +6 -0
  65. package/corpus/templates/analytics/changelog/2026-06-26-dashboard-charts-drag-smoothly-with-stable-cards-inactive-ch.md +6 -0
  66. package/corpus/templates/analytics/changelog/2026-06-26-dashboard-charts-show-a-refresh-spinner-while-keeping-existi.md +6 -0
  67. package/corpus/templates/analytics/changelog/2026-06-26-dashboard-edits-stay-stable-while-chart-order-and-deletions-.md +6 -0
  68. package/corpus/templates/analytics/changelog/2026-06-26-dashboard-email-reports-queue-immediate-sends.md +6 -0
  69. package/corpus/templates/analytics/changelog/2026-06-26-explorer-dashboards-now-drag-charts-with-a-stable-preview-an.md +6 -0
  70. package/corpus/templates/analytics/changelog/2026-06-26-session-replay-playback-can-now-be-toggled-by-clicking-the-r.md +6 -0
  71. package/corpus/templates/analytics/changelog/2026-06-26-session-replays-now-open-from-the-full-row-and-play-with-tim.md +6 -0
  72. package/corpus/templates/analytics/server/lib/dashboard-report-subscriptions.ts +21 -0
  73. package/corpus/templates/analytics/server/lib/dashboard-report.ts +41 -17
  74. package/corpus/templates/analytics/server/plugins/agent-chat.ts +5 -0
  75. package/dist/action-ui.d.ts +1 -0
  76. package/dist/action-ui.d.ts.map +1 -1
  77. package/dist/action-ui.js +1 -0
  78. package/dist/action-ui.js.map +1 -1
  79. package/dist/client/analytics.d.ts.map +1 -1
  80. package/dist/client/analytics.js +173 -12
  81. package/dist/client/analytics.js.map +1 -1
  82. package/dist/client/chat/index.d.ts +1 -1
  83. package/dist/client/chat/index.d.ts.map +1 -1
  84. package/dist/client/chat/index.js +1 -1
  85. package/dist/client/chat/index.js.map +1 -1
  86. package/dist/client/chat/tool-call-display.d.ts.map +1 -1
  87. package/dist/client/chat/tool-call-display.js +3 -1
  88. package/dist/client/chat/tool-call-display.js.map +1 -1
  89. package/dist/client/chat/widgets/InlineExtensionWidget.d.ts +17 -0
  90. package/dist/client/chat/widgets/InlineExtensionWidget.d.ts.map +1 -0
  91. package/dist/client/chat/widgets/InlineExtensionWidget.js +85 -0
  92. package/dist/client/chat/widgets/InlineExtensionWidget.js.map +1 -0
  93. package/dist/client/chat/widgets/builtin-tool-renderers.d.ts.map +1 -1
  94. package/dist/client/chat/widgets/builtin-tool-renderers.js +15 -2
  95. package/dist/client/chat/widgets/builtin-tool-renderers.js.map +1 -1
  96. package/dist/client/conversation/AgentConversation.d.ts.map +1 -1
  97. package/dist/client/conversation/AgentConversation.js +33 -0
  98. package/dist/client/conversation/AgentConversation.js.map +1 -1
  99. package/dist/client/conversation/code-agent-transcript.js +8 -0
  100. package/dist/client/conversation/code-agent-transcript.js.map +1 -1
  101. package/dist/client/conversation/types.d.ts +4 -0
  102. package/dist/client/conversation/types.d.ts.map +1 -1
  103. package/dist/client/conversation/types.js.map +1 -1
  104. package/dist/client/extensions/EmbeddedExtension.d.ts.map +1 -1
  105. package/dist/client/extensions/EmbeddedExtension.js +29 -1
  106. package/dist/client/extensions/EmbeddedExtension.js.map +1 -1
  107. package/dist/client/extensions/ExtensionViewer.d.ts.map +1 -1
  108. package/dist/client/extensions/ExtensionViewer.js +28 -1
  109. package/dist/client/extensions/ExtensionViewer.js.map +1 -1
  110. package/dist/client/extensions/InlineExtensionFrame.d.ts +25 -0
  111. package/dist/client/extensions/InlineExtensionFrame.d.ts.map +1 -0
  112. package/dist/client/extensions/InlineExtensionFrame.js +488 -0
  113. package/dist/client/extensions/InlineExtensionFrame.js.map +1 -0
  114. package/dist/client/extensions/iframe-bridge.d.ts +2 -0
  115. package/dist/client/extensions/iframe-bridge.d.ts.map +1 -1
  116. package/dist/client/extensions/iframe-bridge.js +23 -0
  117. package/dist/client/extensions/iframe-bridge.js.map +1 -1
  118. package/dist/client/extensions/index.d.ts +1 -0
  119. package/dist/client/extensions/index.d.ts.map +1 -1
  120. package/dist/client/extensions/index.js +1 -0
  121. package/dist/client/extensions/index.js.map +1 -1
  122. package/dist/client/index.d.ts +1 -1
  123. package/dist/client/index.d.ts.map +1 -1
  124. package/dist/client/index.js +1 -1
  125. package/dist/client/index.js.map +1 -1
  126. package/dist/client/session-replay.d.ts +11 -1
  127. package/dist/client/session-replay.d.ts.map +1 -1
  128. package/dist/client/session-replay.js +74 -14
  129. package/dist/client/session-replay.js.map +1 -1
  130. package/dist/code-agents/transcript-normalizer.d.ts +2 -0
  131. package/dist/code-agents/transcript-normalizer.d.ts.map +1 -1
  132. package/dist/code-agents/transcript-normalizer.js +8 -0
  133. package/dist/code-agents/transcript-normalizer.js.map +1 -1
  134. package/dist/collab/awareness.d.ts +2 -2
  135. package/dist/collab/awareness.d.ts.map +1 -1
  136. package/dist/collab/routes.d.ts +2 -2
  137. package/dist/extensions/actions.d.ts.map +1 -1
  138. package/dist/extensions/actions.js +200 -1
  139. package/dist/extensions/actions.js.map +1 -1
  140. package/dist/extensions/html-shell.d.ts.map +1 -1
  141. package/dist/extensions/html-shell.js +70 -3
  142. package/dist/extensions/html-shell.js.map +1 -1
  143. package/dist/extensions/routes.d.ts.map +1 -1
  144. package/dist/extensions/routes.js +11 -4
  145. package/dist/extensions/routes.js.map +1 -1
  146. package/dist/file-upload/actions/upload-image.d.ts +2 -2
  147. package/dist/index.browser.d.ts +1 -1
  148. package/dist/index.browser.d.ts.map +1 -1
  149. package/dist/index.browser.js +1 -1
  150. package/dist/index.browser.js.map +1 -1
  151. package/dist/index.d.ts +1 -1
  152. package/dist/index.d.ts.map +1 -1
  153. package/dist/index.js +1 -1
  154. package/dist/index.js.map +1 -1
  155. package/dist/mcp/build-server.js +1 -1
  156. package/dist/mcp/build-server.js.map +1 -1
  157. package/dist/mcp/embed-app.d.ts.map +1 -1
  158. package/dist/mcp/embed-app.js +11 -1
  159. package/dist/mcp/embed-app.js.map +1 -1
  160. package/dist/observability/routes.d.ts +7 -7
  161. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  162. package/dist/resources/handlers.d.ts +2 -2
  163. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  164. package/dist/server/agent-chat-plugin.js +21 -9
  165. package/dist/server/agent-chat-plugin.js.map +1 -1
  166. package/dist/server/agent-engine-api-key-route.d.ts +2 -2
  167. package/dist/templates/workspace-core/.agents/skills/extensions/SKILL.md +13 -0
  168. package/dist/templates/workspace-core/.agents/skills/extensions/references/api.md +2 -0
  169. package/dist/templates/workspace-core/.agents/skills/generative-ui/SKILL.md +115 -0
  170. package/docs/content/actions.md +4 -2
  171. package/docs/content/agent-surfaces.md +9 -0
  172. package/docs/content/extensions.md +10 -0
  173. package/docs/content/generative-ui.md +217 -0
  174. package/docs/content/key-concepts.md +2 -2
  175. package/docs/content/mcp-apps.md +3 -5
  176. package/docs/content/native-chat-ui.md +9 -5
  177. package/docs/content/tracking.md +9 -3
  178. package/package.json +1 -1
  179. package/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +13 -0
  180. package/src/templates/workspace-core/.agents/skills/extensions/references/api.md +2 -0
  181. package/src/templates/workspace-core/.agents/skills/generative-ui/SKILL.md +115 -0
@@ -351,6 +351,7 @@ const enUS = {
351
351
  panelOptions: "Panel options",
352
352
  fullScreen: "Full screen",
353
353
  refresh: "Refresh",
354
+ refreshing: "Refreshing...",
354
355
  downloadCsv: "Download CSV",
355
356
  viewSql: "View SQL",
356
357
  dragToReorder: "Drag to reorder",
@@ -409,6 +410,7 @@ const enUS = {
409
410
  reportSubscriptionSaved: "Email report subscription saved.",
410
411
  reportSubscriptionDeleted: "Email report subscription deleted.",
411
412
  reportSent: "Dashboard report sent.",
413
+ reportQueued: "Dashboard report queued.",
412
414
  reportSubscriptionSaveFailed: "Couldn't save subscription: {{message}}",
413
415
  reportSubscriptionDeleteFailed: "Couldn't delete subscription: {{message}}",
414
416
  reportSendFailed: "Couldn't send report: {{message}}",
@@ -737,6 +739,11 @@ const enUS = {
737
739
  description:
738
740
  "Review first-party browser sessions and replay recordings captured by Agent Native Analytics.",
739
741
  filters: "Filters",
742
+ segmentFilters: "Segment filters",
743
+ sessionPlaylist: "Session playlist",
744
+ userFilters: "User filters",
745
+ eventFilters: "Event filters",
746
+ anyActivity: "Any activity",
740
747
  filtersDescription:
741
748
  "Filters are stored in the URL so the agent and shared links see the same session list.",
742
749
  refresh: "Refresh",
@@ -753,6 +760,8 @@ const enUS = {
753
760
  last90d: "Last 90d",
754
761
  allTime: "All time",
755
762
  showing: "{{count}} sessions",
763
+ eventCountCompact: "{{count}} events",
764
+ pageCountCompact: "{{count}} pages",
756
765
  truncated: "Showing the first replay events only.",
757
766
  session: "Session",
758
767
  visitor: "Visitor",
@@ -775,18 +784,25 @@ const enUS = {
775
784
  installSnippetTitle: "Add session replay",
776
785
  backToSessions: "Back to sessions",
777
786
  askAgent: "Ask agent about this session",
787
+ askSessionTitle: "Ask about this session",
788
+ askSessionDescription:
789
+ "Send a focused prompt to the Analytics agent with this replay attached as context.",
790
+ askSessionPlaceholder: "What happened in this session?",
778
791
  replayPlayer: "Replay player",
779
792
  replayLoading: "Loading replay...",
780
- replayUnavailable: "No replay chunks for this session",
793
+ replayUnavailable: "No playable replay for this session",
781
794
  replayUnavailableDescription:
782
- "This recording has metadata, but no playable replay chunks were found.",
783
- unavailableChunks: "{{count}} chunks could not be loaded.",
795
+ "This recording has metadata, but no playable replay events were found.",
796
+ unavailableChunks: "{{count}} replay segments could not be loaded.",
784
797
  replayChunks: "Replay chunks",
785
798
  replayChunksDescription:
786
799
  "Scoped chunks used to reconstruct this replay. Provider URLs stay private.",
787
800
  chunkAndEventCount: "{{chunks}} chunks, {{events}} replay events",
801
+ replayEventCount: "{{events}} replay events",
788
802
  timeline: "Event timeline",
803
+ replayTimeline: "Replay timeline",
789
804
  timelineDescription: "Showing the first {{count}} events in this session.",
805
+ noTimelineEvents: "No timeline markers found",
790
806
  sequence: "Sequence",
791
807
  size: "Size",
792
808
  checksum: "Checksum",
@@ -800,8 +816,13 @@ const enUS = {
800
816
  restart: "Restart",
801
817
  play: "Play",
802
818
  pause: "Pause",
819
+ skipBack: "Back 5 seconds",
820
+ skipForward: "Forward 5 seconds",
821
+ skipInactive: "Skip inactivity",
822
+ skipInactiveOn: "Skipping inactive gaps",
823
+ skipInactiveOff: "Playing inactive gaps",
803
824
  loadFailed: "Couldn't load session replay: {{message}}",
804
- noReplayEvents: "No rrweb events were found in the replay chunks.",
825
+ noReplayEvents: "No rrweb events were found for this replay.",
805
826
  chunkCount: "{{count}} replay chunks",
806
827
  url: "URL",
807
828
  path: "Path",
@@ -6529,22 +6550,237 @@ const translatedAnalyticsDebtCorrections = {
6529
6550
  team: "الفريق - Analytics",
6530
6551
  tool: "الأداة - Analytics",
6531
6552
  },
6553
+ sessions: {
6554
+ segmentFilters: "عوامل تصفية الشرائح",
6555
+ sessionPlaylist: "قائمة تشغيل الجلسات",
6556
+ userFilters: "عوامل تصفية المستخدم",
6557
+ eventFilters: "عوامل تصفية الأحداث",
6558
+ anyActivity: "أي نشاط",
6559
+ eventCountCompact: "{{count}} حدث",
6560
+ pageCountCompact: "{{count}} صفحة",
6561
+ askSessionTitle: "اسأل عن هذه الجلسة",
6562
+ askSessionDescription:
6563
+ "أرسل مطالبة مركزة إلى وكيل Analytics مع إرفاق هذا التسجيل كسياق.",
6564
+ askSessionPlaceholder: "ماذا حدث في هذه الجلسة؟",
6565
+ replayTimeline: "خط إعادة التشغيل الزمني",
6566
+ noTimelineEvents: "لم يتم العثور على علامات في الخط الزمني",
6567
+ skipBack: "الرجوع 5 ثوانٍ",
6568
+ skipForward: "التقدم 5 ثوانٍ",
6569
+ skipInactive: "تخطي فترات الخمول",
6570
+ skipInactiveOn: "يتم تخطي الفجوات الخاملة",
6571
+ skipInactiveOff: "تشغيل الفجوات الخاملة",
6572
+ },
6532
6573
  sqlDashboard: {
6533
6574
  addDescriptionPlaceholder: "أضف وصفًا",
6534
6575
  collapseFilters: "طي عوامل التصفية",
6576
+ refreshing: "جارٍ التحديث...",
6535
6577
  },
6536
6578
  },
6537
6579
  "de-DE": {
6538
6580
  routeTitles: {
6539
6581
  team: "Team-Bereich - Analytics",
6540
6582
  },
6583
+ sessions: {
6584
+ segmentFilters: "Segmentfilter",
6585
+ sessionPlaylist: "Sitzungs-Playlist",
6586
+ userFilters: "Benutzerfilter",
6587
+ eventFilters: "Ereignisfilter",
6588
+ anyActivity: "Beliebige Aktivität",
6589
+ eventCountCompact: "{{count}} Ereignisse",
6590
+ pageCountCompact: "{{count}} Seiten",
6591
+ askSessionTitle: "Zu dieser Sitzung fragen",
6592
+ askSessionDescription:
6593
+ "Sende dem Analytics-Agenten eine gezielte Eingabe mit dieser Wiedergabe als Kontext.",
6594
+ askSessionPlaceholder: "Was ist in dieser Sitzung passiert?",
6595
+ replayTimeline: "Wiedergabe-Zeitachse",
6596
+ noTimelineEvents: "Keine Zeitachsenmarker gefunden",
6597
+ skipBack: "5 Sekunden zurück",
6598
+ skipForward: "5 Sekunden vor",
6599
+ skipInactive: "Inaktivität überspringen",
6600
+ skipInactiveOn: "Inaktive Lücken werden übersprungen",
6601
+ skipInactiveOff: "Inaktive Lücken werden abgespielt",
6602
+ },
6603
+ sqlDashboard: {
6604
+ refreshing: "Wird aktualisiert...",
6605
+ },
6606
+ },
6607
+ "es-ES": {
6608
+ sessions: {
6609
+ segmentFilters: "Filtros de segmento",
6610
+ sessionPlaylist: "Lista de sesiones",
6611
+ userFilters: "Filtros de usuario",
6612
+ eventFilters: "Filtros de eventos",
6613
+ anyActivity: "Cualquier actividad",
6614
+ eventCountCompact: "{{count}} eventos",
6615
+ pageCountCompact: "{{count}} páginas",
6616
+ askSessionTitle: "Preguntar sobre esta sesión",
6617
+ askSessionDescription:
6618
+ "Envía una pregunta enfocada al agente de Analytics con esta reproducción como contexto.",
6619
+ askSessionPlaceholder: "¿Qué pasó en esta sesión?",
6620
+ replayTimeline: "Línea de tiempo de reproducción",
6621
+ noTimelineEvents: "No se encontraron marcadores de línea de tiempo",
6622
+ skipBack: "Retroceder 5 segundos",
6623
+ skipForward: "Avanzar 5 segundos",
6624
+ skipInactive: "Omitir inactividad",
6625
+ skipInactiveOn: "Omitiendo pausas inactivas",
6626
+ skipInactiveOff: "Reproduciendo pausas inactivas",
6627
+ },
6628
+ sqlDashboard: {
6629
+ refreshing: "Actualizando...",
6630
+ },
6541
6631
  },
6542
6632
  "fr-FR": {
6543
6633
  routeTitles: {
6544
6634
  analyses: "Liste des analyses - Analytics",
6545
6635
  },
6636
+ sessions: {
6637
+ segmentFilters: "Filtres de segment",
6638
+ sessionPlaylist: "Liste de sessions",
6639
+ userFilters: "Filtres utilisateur",
6640
+ eventFilters: "Filtres d'événement",
6641
+ anyActivity: "Toute activité",
6642
+ eventCountCompact: "{{count}} événements",
6643
+ pageCountCompact: "{{count}} pages",
6644
+ askSessionTitle: "Poser une question sur cette session",
6645
+ askSessionDescription:
6646
+ "Envoyez une question ciblée à l'agent Analytics avec cette relecture en contexte.",
6647
+ askSessionPlaceholder: "Que s'est-il passé dans cette session ?",
6648
+ replayTimeline: "Chronologie de relecture",
6649
+ noTimelineEvents: "Aucun marqueur de chronologie trouvé",
6650
+ skipBack: "Reculer de 5 secondes",
6651
+ skipForward: "Avancer de 5 secondes",
6652
+ skipInactive: "Ignorer l'inactivité",
6653
+ skipInactiveOn: "Les périodes inactives sont ignorées",
6654
+ skipInactiveOff: "Les périodes inactives sont lues",
6655
+ },
6546
6656
  sqlDashboard: {
6547
6657
  formatSql: "Formater SQL",
6658
+ refreshing: "Actualisation...",
6659
+ },
6660
+ },
6661
+ "hi-IN": {
6662
+ sessions: {
6663
+ segmentFilters: "सेगमेंट फ़िल्टर",
6664
+ sessionPlaylist: "सत्र प्लेलिस्ट",
6665
+ userFilters: "उपयोगकर्ता फ़िल्टर",
6666
+ eventFilters: "इवेंट फ़िल्टर",
6667
+ anyActivity: "कोई भी गतिविधि",
6668
+ eventCountCompact: "{{count}} इवेंट",
6669
+ pageCountCompact: "{{count}} पेज",
6670
+ askSessionTitle: "इस सत्र के बारे में पूछें",
6671
+ askSessionDescription:
6672
+ "इस रीप्ले को संदर्भ के रूप में जोड़कर Analytics एजेंट को केंद्रित प्रॉम्प्ट भेजें।",
6673
+ askSessionPlaceholder: "इस सत्र में क्या हुआ?",
6674
+ replayTimeline: "रीप्ले टाइमलाइन",
6675
+ noTimelineEvents: "कोई टाइमलाइन मार्कर नहीं मिला",
6676
+ skipBack: "5 सेकंड पीछे",
6677
+ skipForward: "5 सेकंड आगे",
6678
+ skipInactive: "निष्क्रियता छोड़ें",
6679
+ skipInactiveOn: "निष्क्रिय अंतराल छोड़े जा रहे हैं",
6680
+ skipInactiveOff: "निष्क्रिय अंतराल चलाए जा रहे हैं",
6681
+ },
6682
+ sqlDashboard: {
6683
+ refreshing: "रीफ़्रेश हो रहा है...",
6684
+ },
6685
+ },
6686
+ "ja-JP": {
6687
+ sessions: {
6688
+ segmentFilters: "セグメントフィルター",
6689
+ sessionPlaylist: "セッションプレイリスト",
6690
+ userFilters: "ユーザーフィルター",
6691
+ eventFilters: "イベントフィルター",
6692
+ anyActivity: "任意のアクティビティ",
6693
+ eventCountCompact: "{{count}} 件のイベント",
6694
+ pageCountCompact: "{{count}} ページ",
6695
+ askSessionTitle: "このセッションについて質問",
6696
+ askSessionDescription:
6697
+ "このリプレイをコンテキストとして添えて、Analytics エージェントに絞り込んだプロンプトを送信します。",
6698
+ askSessionPlaceholder: "このセッションで何が起きましたか?",
6699
+ replayTimeline: "リプレイタイムライン",
6700
+ noTimelineEvents: "タイムラインマーカーが見つかりません",
6701
+ skipBack: "5 秒戻る",
6702
+ skipForward: "5 秒進む",
6703
+ skipInactive: "非アクティブ時間をスキップ",
6704
+ skipInactiveOn: "非アクティブな間隔をスキップ中",
6705
+ skipInactiveOff: "非アクティブな間隔を再生中",
6706
+ },
6707
+ sqlDashboard: {
6708
+ refreshing: "更新中...",
6709
+ },
6710
+ },
6711
+ "ko-KR": {
6712
+ sessions: {
6713
+ segmentFilters: "세그먼트 필터",
6714
+ sessionPlaylist: "세션 재생 목록",
6715
+ userFilters: "사용자 필터",
6716
+ eventFilters: "이벤트 필터",
6717
+ anyActivity: "모든 활동",
6718
+ eventCountCompact: "{{count}}개 이벤트",
6719
+ pageCountCompact: "{{count}}개 페이지",
6720
+ askSessionTitle: "이 세션에 대해 질문",
6721
+ askSessionDescription:
6722
+ "이 리플레이를 컨텍스트로 첨부해 Analytics 에이전트에 집중된 프롬프트를 보냅니다.",
6723
+ askSessionPlaceholder: "이 세션에서 무슨 일이 있었나요?",
6724
+ replayTimeline: "리플레이 타임라인",
6725
+ noTimelineEvents: "타임라인 마커를 찾지 못했습니다",
6726
+ skipBack: "5초 뒤로",
6727
+ skipForward: "5초 앞으로",
6728
+ skipInactive: "비활성 시간 건너뛰기",
6729
+ skipInactiveOn: "비활성 구간을 건너뛰는 중",
6730
+ skipInactiveOff: "비활성 구간을 재생하는 중",
6731
+ },
6732
+ sqlDashboard: {
6733
+ refreshing: "새로고침 중...",
6734
+ },
6735
+ },
6736
+ "pt-BR": {
6737
+ sessions: {
6738
+ segmentFilters: "Filtros de segmento",
6739
+ sessionPlaylist: "Playlist de sessões",
6740
+ userFilters: "Filtros de usuário",
6741
+ eventFilters: "Filtros de eventos",
6742
+ anyActivity: "Qualquer atividade",
6743
+ eventCountCompact: "{{count}} eventos",
6744
+ pageCountCompact: "{{count}} páginas",
6745
+ askSessionTitle: "Perguntar sobre esta sessão",
6746
+ askSessionDescription:
6747
+ "Envie um prompt focado ao agente de Analytics com este replay como contexto.",
6748
+ askSessionPlaceholder: "O que aconteceu nesta sessão?",
6749
+ replayTimeline: "Linha do tempo do replay",
6750
+ noTimelineEvents: "Nenhum marcador de linha do tempo encontrado",
6751
+ skipBack: "Voltar 5 segundos",
6752
+ skipForward: "Avançar 5 segundos",
6753
+ skipInactive: "Pular inatividade",
6754
+ skipInactiveOn: "Pulando lacunas inativas",
6755
+ skipInactiveOff: "Reproduzindo lacunas inativas",
6756
+ },
6757
+ sqlDashboard: {
6758
+ refreshing: "Atualizando...",
6759
+ },
6760
+ },
6761
+ "zh-CN": {
6762
+ sessions: {
6763
+ segmentFilters: "分段筛选器",
6764
+ sessionPlaylist: "会话播放列表",
6765
+ userFilters: "用户筛选器",
6766
+ eventFilters: "事件筛选器",
6767
+ anyActivity: "任意活动",
6768
+ eventCountCompact: "{{count}} 个事件",
6769
+ pageCountCompact: "{{count}} 个页面",
6770
+ askSessionTitle: "询问此会话",
6771
+ askSessionDescription:
6772
+ "将此回放作为上下文,向 Analytics 代理发送聚焦提示。",
6773
+ askSessionPlaceholder: "此会话中发生了什么?",
6774
+ replayTimeline: "回放时间线",
6775
+ noTimelineEvents: "未找到时间线标记",
6776
+ skipBack: "后退 5 秒",
6777
+ skipForward: "前进 5 秒",
6778
+ skipInactive: "跳过非活动时间",
6779
+ skipInactiveOn: "正在跳过非活动间隔",
6780
+ skipInactiveOff: "正在播放非活动间隔",
6781
+ },
6782
+ sqlDashboard: {
6783
+ refreshing: "正在刷新...",
6548
6784
  },
6549
6785
  },
6550
6786
  } satisfies Partial<Record<LocaleCode, AnalyticsPartialMessages>>;
@@ -7536,6 +7772,7 @@ const translatedDashboardReportTranslations = {
7536
7772
  reportSubscriptionSaved: "电子邮件报告订阅已保存。",
7537
7773
  reportSubscriptionDeleted: "电子邮件报告订阅已删除。",
7538
7774
  reportSent: "仪表板报告已发送。",
7775
+ reportQueued: "仪表板报告已加入队列。",
7539
7776
  reportSubscriptionSaveFailed: "无法保存订阅:{{message}}",
7540
7777
  reportSubscriptionDeleteFailed: "无法删除订阅:{{message}}",
7541
7778
  reportSendFailed: "无法发送报告:{{message}}",
@@ -7568,6 +7805,7 @@ const translatedDashboardReportTranslations = {
7568
7805
  reportSubscriptionSaved: "Suscripción al informe guardada.",
7569
7806
  reportSubscriptionDeleted: "Suscripción al informe eliminada.",
7570
7807
  reportSent: "Informe del panel enviado.",
7808
+ reportQueued: "Informe del panel en cola.",
7571
7809
  reportSubscriptionSaveFailed:
7572
7810
  "No se pudo guardar la suscripción: {{message}}",
7573
7811
  reportSubscriptionDeleteFailed:
@@ -7603,6 +7841,7 @@ const translatedDashboardReportTranslations = {
7603
7841
  reportSubscriptionSaved: "Abonnement au rapport enregistré.",
7604
7842
  reportSubscriptionDeleted: "Abonnement au rapport supprimé.",
7605
7843
  reportSent: "Rapport du tableau de bord envoyé.",
7844
+ reportQueued: "Rapport du tableau de bord mis en file d'attente.",
7606
7845
  reportSubscriptionSaveFailed:
7607
7846
  "Impossible d'enregistrer l'abonnement : {{message}}",
7608
7847
  reportSubscriptionDeleteFailed:
@@ -7637,6 +7876,7 @@ const translatedDashboardReportTranslations = {
7637
7876
  reportSubscriptionSaved: "E-Mail-Bericht-Abonnement gespeichert.",
7638
7877
  reportSubscriptionDeleted: "E-Mail-Bericht-Abonnement gelöscht.",
7639
7878
  reportSent: "Dashboard-Bericht gesendet.",
7879
+ reportQueued: "Dashboard-Bericht in die Warteschlange gestellt.",
7640
7880
  reportSubscriptionSaveFailed:
7641
7881
  "Abonnement konnte nicht gespeichert werden: {{message}}",
7642
7882
  reportSubscriptionDeleteFailed:
@@ -7671,6 +7911,7 @@ const translatedDashboardReportTranslations = {
7671
7911
  reportSubscriptionSaved: "メールレポートの購読を保存しました。",
7672
7912
  reportSubscriptionDeleted: "メールレポートの購読を削除しました。",
7673
7913
  reportSent: "ダッシュボードレポートを送信しました。",
7914
+ reportQueued: "ダッシュボードレポートをキューに追加しました。",
7674
7915
  reportSubscriptionSaveFailed: "購読を保存できませんでした: {{message}}",
7675
7916
  reportSubscriptionDeleteFailed: "購読を削除できませんでした: {{message}}",
7676
7917
  reportSendFailed: "レポートを送信できませんでした: {{message}}",
@@ -7703,6 +7944,7 @@ const translatedDashboardReportTranslations = {
7703
7944
  reportSubscriptionSaved: "이메일 보고서 구독이 저장되었습니다.",
7704
7945
  reportSubscriptionDeleted: "이메일 보고서 구독이 삭제되었습니다.",
7705
7946
  reportSent: "대시보드 보고서가 전송되었습니다.",
7947
+ reportQueued: "대시보드 보고서가 대기열에 추가되었습니다.",
7706
7948
  reportSubscriptionSaveFailed: "구독을 저장할 수 없음: {{message}}",
7707
7949
  reportSubscriptionDeleteFailed: "구독을 삭제할 수 없음: {{message}}",
7708
7950
  reportSendFailed: "보고서를 전송할 수 없음: {{message}}",
@@ -7735,6 +7977,7 @@ const translatedDashboardReportTranslations = {
7735
7977
  reportSubscriptionSaved: "Assinatura do relatório por e-mail salva.",
7736
7978
  reportSubscriptionDeleted: "Assinatura do relatório por e-mail excluída.",
7737
7979
  reportSent: "Relatório do painel enviado.",
7980
+ reportQueued: "Relatório do painel enfileirado.",
7738
7981
  reportSubscriptionSaveFailed:
7739
7982
  "Não foi possível salvar a assinatura: {{message}}",
7740
7983
  reportSubscriptionDeleteFailed:
@@ -7768,6 +8011,7 @@ const translatedDashboardReportTranslations = {
7768
8011
  reportSubscriptionSaved: "ईमेल रिपोर्ट सब्सक्रिप्शन सहेजा गया।",
7769
8012
  reportSubscriptionDeleted: "ईमेल रिपोर्ट सब्सक्रिप्शन हटाया गया।",
7770
8013
  reportSent: "डैशबोर्ड रिपोर्ट भेजी गई।",
8014
+ reportQueued: "डैशबोर्ड रिपोर्ट कतार में डाली गई।",
7771
8015
  reportSubscriptionSaveFailed: "सब्सक्रिप्शन सहेजा नहीं जा सका: {{message}}",
7772
8016
  reportSubscriptionDeleteFailed: "सब्सक्रिप्शन हटाया नहीं जा सका: {{message}}",
7773
8017
  reportSendFailed: "रिपोर्ट भेजी नहीं जा सकी: {{message}}",
@@ -7799,6 +8043,7 @@ const translatedDashboardReportTranslations = {
7799
8043
  reportSubscriptionSaved: "تم حفظ اشتراك تقرير البريد الإلكتروني.",
7800
8044
  reportSubscriptionDeleted: "تم حذف اشتراك تقرير البريد الإلكتروني.",
7801
8045
  reportSent: "تم إرسال تقرير لوحة المعلومات.",
8046
+ reportQueued: "تمت إضافة تقرير لوحة المعلومات إلى قائمة الانتظار.",
7802
8047
  reportSubscriptionSaveFailed: "تعذر حفظ الاشتراك: {{message}}",
7803
8048
  reportSubscriptionDeleteFailed: "تعذر حذف الاشتراك: {{message}}",
7804
8049
  reportSendFailed: "تعذر إرسال التقرير: {{message}}",
@@ -80,10 +80,9 @@ export function DashboardChartCard({
80
80
  } = useSortable({ id: chart.id, disabled: !editable });
81
81
 
82
82
  const style = {
83
- transform: CSS.Transform.toString(transform),
83
+ transform: isDragging ? undefined : CSS.Transform.toString(transform),
84
84
  transition,
85
85
  zIndex: isDragging ? 50 : undefined,
86
- opacity: isDragging ? 0.7 : 1,
87
86
  };
88
87
 
89
88
  const { data: config } = useQuery({
@@ -106,6 +105,7 @@ export function DashboardChartCard({
106
105
  <div
107
106
  ref={setNodeRef}
108
107
  style={style}
108
+ data-dragging={isDragging ? "true" : undefined}
109
109
  className={`group relative ${chart.width === 2 ? "md:col-span-2" : ""}`}
110
110
  >
111
111
  <Card className="h-full">
@@ -172,7 +172,7 @@ export function DashboardChartCard({
172
172
  </div>
173
173
  ) : null}
174
174
  </CardHeader>
175
- <CardContent className="pt-0">
175
+ <CardContent className="explorer-dashboard-chart-content pt-0">
176
176
  {isLoading ? (
177
177
  <Skeleton className="h-48 w-full" />
178
178
  ) : config ? (
@@ -14,12 +14,14 @@ import {
14
14
  } from "@agent-native/core/client";
15
15
  import {
16
16
  DndContext,
17
+ DragOverlay,
17
18
  closestCenter,
18
19
  PointerSensor,
19
20
  KeyboardSensor,
20
21
  useSensor,
21
22
  useSensors,
22
23
  type DragEndEvent,
24
+ type DragStartEvent,
23
25
  } from "@dnd-kit/core";
24
26
  import {
25
27
  arrayMove,
@@ -35,6 +37,7 @@ import {
35
37
  IconDots,
36
38
  IconEye,
37
39
  IconEyeOff,
40
+ IconGripVertical,
38
41
  } from "@tabler/icons-react";
39
42
  import { useQuery, useQueryClient } from "@tanstack/react-query";
40
43
  import { useState, useEffect, useCallback } from "react";
@@ -111,6 +114,17 @@ type FetchedExplorerDashboard = {
111
114
  hiddenBy: string | null;
112
115
  } & ResourceAccess;
113
116
 
117
+ function ExplorerDashboardDragPreview({ title }: { title: string | null }) {
118
+ if (!title) return null;
119
+
120
+ return (
121
+ <div className="explorer-dashboard-drag-preview flex max-w-64 items-center gap-2 rounded-md border bg-background/95 px-3 py-2 text-sm font-medium text-foreground shadow-lg ring-1 ring-primary/20">
122
+ <IconGripVertical className="h-4 w-4 shrink-0 text-muted-foreground" />
123
+ <span className="truncate">{title}</span>
124
+ </div>
125
+ );
126
+ }
127
+
114
128
  async function fetchDashboard(
115
129
  id: string,
116
130
  ): Promise<FetchedExplorerDashboard | null> {
@@ -181,6 +195,9 @@ export default function ExplorerDashboardPage() {
181
195
  const [addChartOpen, setAddChartOpen] = useState(false);
182
196
  const [loaded, setLoaded] = useState(false);
183
197
  const [confirmDeleteOpen, setConfirmDeleteOpen] = useState(false);
198
+ const [activeDragChartId, setActiveDragChartId] = useState<string | null>(
199
+ null,
200
+ );
184
201
  const canEdit = resourceCanEdit(resourceAccess);
185
202
  const canManage = resourceCanManage(resourceAccess);
186
203
  const { mutateAsync: hideDashboardAction, isPending: unhidePending } =
@@ -456,8 +473,13 @@ export default function ExplorerDashboardPage() {
456
473
  }),
457
474
  );
458
475
 
476
+ const handleDragStart = useCallback((event: DragStartEvent) => {
477
+ setActiveDragChartId(String(event.active.id));
478
+ }, []);
479
+
459
480
  const handleDragEnd = useCallback(
460
481
  (event: DragEndEvent) => {
482
+ setActiveDragChartId(null);
461
483
  if (!dashboard || !canEdit) return;
462
484
  const { active, over } = event;
463
485
  if (!over || active.id === over.id) return;
@@ -472,6 +494,10 @@ export default function ExplorerDashboardPage() {
472
494
  [dashboard, canEdit, persist],
473
495
  );
474
496
 
497
+ const handleDragCancel = useCallback(() => {
498
+ setActiveDragChartId(null);
499
+ }, []);
500
+
475
501
  const handleSaveName = useCallback(() => {
476
502
  if (!dashboard || !canEdit) return;
477
503
  const name = nameInput.trim() || t("explorerDashboard.untitledDashboard");
@@ -509,6 +535,12 @@ export default function ExplorerDashboardPage() {
509
535
 
510
536
  // Config name lookup
511
537
  const configNameMap = new Map(savedConfigs.map((c) => [c.id, c.name]));
538
+ const activeDragChart = activeDragChartId
539
+ ? (dashboard.charts.find((chart) => chart.id === activeDragChartId) ?? null)
540
+ : null;
541
+ const activeDragChartTitle = activeDragChart
542
+ ? (configNameMap.get(activeDragChart.configId) ?? activeDragChart.configId)
543
+ : null;
512
544
 
513
545
  return (
514
546
  <div className="space-y-4">
@@ -700,13 +732,18 @@ export default function ExplorerDashboardPage() {
700
732
  <DndContext
701
733
  sensors={sensors}
702
734
  collisionDetection={closestCenter}
735
+ onDragStart={canEdit ? handleDragStart : undefined}
703
736
  onDragEnd={canEdit ? handleDragEnd : undefined}
737
+ onDragCancel={handleDragCancel}
704
738
  >
705
739
  <SortableContext
706
740
  items={dashboard.charts.map((c) => c.id)}
707
741
  strategy={rectSortingStrategy}
708
742
  >
709
- <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
743
+ <div
744
+ className="explorer-dashboard-grid grid grid-cols-1 md:grid-cols-2 gap-4"
745
+ data-dashboard-dragging={activeDragChartId ? "true" : undefined}
746
+ >
710
747
  {dashboard.charts.map((chart) => (
711
748
  <DashboardChartCard
712
749
  key={chart.id}
@@ -724,6 +761,9 @@ export default function ExplorerDashboardPage() {
724
761
  ))}
725
762
  </div>
726
763
  </SortableContext>
764
+ <DragOverlay adjustScale={false} dropAnimation={null} zIndex={1000}>
765
+ <ExplorerDashboardDragPreview title={activeDragChartTitle} />
766
+ </DragOverlay>
727
767
  </DndContext>
728
768
  )}
729
769
 
@@ -231,7 +231,7 @@ export function EmailReportDialog({
231
231
  try {
232
232
  await sendNow.mutateAsync({ id: selectedId });
233
233
  await refetch();
234
- toast.success(t("sqlDashboard.reportSent"));
234
+ toast.success(t("sqlDashboard.reportQueued"));
235
235
  } catch (err: any) {
236
236
  toast.error(
237
237
  t("sqlDashboard.reportSendFailed", {
@@ -225,11 +225,11 @@ function PanelEditorContent({
225
225
  message: trimmed,
226
226
  context:
227
227
  `The user wants to add a new panel to SQL dashboard "${dashboardId}". ${titlesLine} ` +
228
- `REAL_DATA_REQUIRED: before saving or answering, run at least one real data-source query action for this panel; \`data-source-status\`, \`list-data-dictionary\`, \`update-dashboard\`, and dry-run validation do not count as data queries. ` +
228
+ `REAL_DATA_REQUIRED: before saving or answering, run at least one real data-source query action for this panel; \`data-source-status\`, \`list-data-dictionary\`, \`update-dashboard\`, \`mutate-dashboard\`, and dry-run validation do not count as data queries. ` +
229
229
  `The \`demo\` source is reserved for the built-in Node Exporter demo and does not satisfy REAL_DATA_REQUIRED unless the user explicitly asks to work on that demo dashboard. ` +
230
230
  `If no source can answer, report the exact unavailable/error result instead of saving a panel with guessed schema or metrics. ` +
231
- `Use the \`update-dashboard\` action with ops=[{op:'insert', path:'/panels/-', value: <panel>}] ` +
232
- `to append, or an appropriate index to place the panel in the right spot. ` +
231
+ `Use the \`mutate-dashboard\` action with code like \`dashboard.insertPanel({"id":"new-panel","title":"New Panel","source":"first-party","chartType":"metric","width":1,"sql":"SELECT COUNT(*) AS value FROM analytics_events"}).atBottom();\` ` +
232
+ `to append, or \`.before("panel-id")\`, \`.after("panel-id")\`, or \`.atIndex(n)\` to place the panel. ` +
233
233
  `Panel shape: { id (unique slug), title, sql, source ('bigquery'|'ga4'|'amplitude'|'first-party'|'demo'|'prometheus'), chartType ('line'|'area'|'bar'|'metric'|'table'|'pie'|'section'), width (legacy integer 1..6; set to 1 unless editing existing data), tab? (use 'Group / Tab' for grouped tabs), columns? (section panels only - 1..6 max panels per row for panels following this section), config? }. ` +
234
234
  `Visible layout auto-fits by row: one panel in a row spans the row, two split it, three split it into thirds, up to the section column limit. ` +
235
235
  `For amplitude panels, sql is a JSON descriptor: {"event":"event name","groupBy":"property","days":30}. ` +
@@ -240,7 +240,7 @@ function PanelEditorContent({
240
240
  `Chart legends render automatically; set config.legend=false only when the user explicitly asks to hide the legend. ` +
241
241
  `Consult the data dictionary first via \`list-data-dictionary --search <topic>\`, then use AGENTS.md, .agents/skills, and connected data-source instructions before writing SQL. ` +
242
242
  `Every BigQuery panel is dry-run validated on save — if columns/tables are wrong the save returns a 400 with the BQ error and you must fix the SQL and retry. ` +
243
- `After the panel saves, call \`refresh-screen\` so the UI picks up the change.`,
243
+ `After the mutation saves, verify the returned panelCount, appliedOps, and insertedPanelIds; the UI refreshes automatically.`,
244
244
  submit: true,
245
245
  });
246
246
  onOpenChange(false);