@graph8/sdk 0.362.0 → 0.373.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 (615) hide show
  1. package/README.md +33 -10
  2. package/blocks/_foundation/README.md +78 -1
  3. package/blocks/_foundation/block.json +123 -6
  4. package/blocks/_foundation/components/api-error.tsx +9 -7
  5. package/blocks/_foundation/components/brand-provider.tsx +23 -0
  6. package/blocks/_foundation/components/confirm-spend-dialog.tsx +15 -8
  7. package/blocks/_foundation/components/confirmed-action.tsx +90 -0
  8. package/blocks/_foundation/components/connect-graph8.tsx +280 -0
  9. package/blocks/_foundation/components/empty-state.tsx +5 -2
  10. package/blocks/_foundation/components/list-select.tsx +112 -0
  11. package/blocks/_foundation/components/paging-notices.tsx +55 -0
  12. package/blocks/_foundation/components/screen/detail-panel.tsx +2 -1
  13. package/blocks/_foundation/components/screen/filter-controls.tsx +92 -0
  14. package/blocks/_foundation/components/screen/index.ts +2 -0
  15. package/blocks/_foundation/components/screen/record-link.tsx +76 -0
  16. package/blocks/_foundation/components/screen/split-view.tsx +1 -1
  17. package/blocks/_foundation/components/screen/time-series-chart-recharts.tsx +65 -0
  18. package/blocks/_foundation/components/screen/time-series-chart.tsx +15 -97
  19. package/blocks/_foundation/components/screen/time-series-format.ts +57 -0
  20. package/blocks/_foundation/hooks/use-all-pages.ts +54 -0
  21. package/blocks/_foundation/hooks/use-brand.ts +52 -0
  22. package/blocks/_foundation/hooks/use-g8-mutation.ts +23 -0
  23. package/blocks/_foundation/hooks/use-g8-query.ts +127 -1
  24. package/blocks/_foundation/hooks/use-load-more-list.ts +61 -0
  25. package/blocks/_foundation/hooks/use-paginated.ts +120 -0
  26. package/blocks/_foundation/hooks/use-row-activation.ts +57 -0
  27. package/blocks/_foundation/hooks/use-url-filters.ts +93 -0
  28. package/blocks/_foundation/lib/g8-cache.ts +454 -0
  29. package/blocks/_foundation/lib/g8-client.ts +1 -1
  30. package/blocks/_foundation/lib/paging.ts +57 -0
  31. package/blocks/_foundation/lib/plural.ts +23 -0
  32. package/blocks/_foundation/lib/use-debounced-value.ts +13 -0
  33. package/blocks/_foundation/server/connect-route.ts +15 -0
  34. package/blocks/_foundation/server/connect.ts +127 -0
  35. package/blocks/_foundation/server/local-key.ts +70 -0
  36. package/blocks/_foundation/server/proxy.ts +103 -3
  37. package/blocks/_foundation/server/route.ts +16 -4
  38. package/blocks/agents/README.md +93 -2
  39. package/blocks/agents/block.json +343 -2
  40. package/blocks/agents/components/agent-activity.tsx +112 -0
  41. package/blocks/agents/components/agent-approvals.tsx +135 -0
  42. package/blocks/agents/components/agent-builder.tsx +29 -10
  43. package/blocks/agents/components/agent-conversations.tsx +143 -0
  44. package/blocks/agents/components/agent-knowledge-panel.tsx +4 -3
  45. package/blocks/agents/components/agent-operators.tsx +164 -0
  46. package/blocks/agents/components/agent-run-detail.tsx +119 -0
  47. package/blocks/agents/components/agent-runs.tsx +19 -10
  48. package/blocks/agents/components/agent-skills-panel.tsx +7 -7
  49. package/blocks/agents/components/agent-test-history.tsx +121 -0
  50. package/blocks/agents/components/agents-screen.tsx +226 -0
  51. package/blocks/agents/components/assistant-sessions.tsx +150 -0
  52. package/blocks/agents/components/duplicate-agent-button.tsx +42 -0
  53. package/blocks/agents/components/from-template-button.tsx +65 -0
  54. package/blocks/agents/components/knowledge-browser.tsx +107 -0
  55. package/blocks/agents/components/knowledge-detail.tsx +156 -0
  56. package/blocks/agents/components/knowledge-form.tsx +69 -0
  57. package/blocks/agents/components/name-dialog.tsx +32 -0
  58. package/blocks/agents/components/receptionist-button.tsx +46 -0
  59. package/blocks/agents/components/save-as-template-button.tsx +32 -0
  60. package/blocks/agents/components/skill-editor.tsx +147 -0
  61. package/blocks/agents/components/skill-library.tsx +111 -0
  62. package/blocks/agents/lib/agent-types.ts +7 -1
  63. package/blocks/agents/lib/facts.tsx +13 -0
  64. package/blocks/agents/lib/knowledge-utils.ts +49 -0
  65. package/blocks/agents/lib/load-more.tsx +141 -0
  66. package/blocks/agents/lib/skill-utils.ts +91 -0
  67. package/blocks/agents/recipes/create-agent-and-attach-skill.ts +1 -1
  68. package/blocks/analytics/README.md +13 -0
  69. package/blocks/analytics/block.json +45 -1
  70. package/blocks/analytics/components/analytics-screen.tsx +222 -0
  71. package/blocks/analytics/components/kpi-tiles.tsx +1 -1
  72. package/blocks/analytics/components/leaderboard.tsx +14 -7
  73. package/blocks/analytics/components/report-builder.tsx +38 -11
  74. package/blocks/analytics/components/report-detail.tsx +84 -0
  75. package/blocks/analytics/components/trend-chart.tsx +62 -0
  76. package/blocks/appointments/README.md +6 -0
  77. package/blocks/appointments/block.json +33 -2
  78. package/blocks/appointments/components/availability-editor.tsx +17 -5
  79. package/blocks/appointments/components/booking-page.tsx +2 -2
  80. package/blocks/appointments/components/event-type-editor.tsx +2 -1
  81. package/blocks/appointments/components/event-type-related.tsx +4 -2
  82. package/blocks/appointments/components/meeting-contact-links.tsx +49 -0
  83. package/blocks/appointments/components/meeting-detail.tsx +2 -2
  84. package/blocks/appointments/components/meeting-list.tsx +38 -18
  85. package/blocks/appointments/components/meetings-screen.tsx +7 -4
  86. package/blocks/appointments/components/record-meetings-tab.tsx +92 -0
  87. package/blocks/appointments/components/scheduling-screen.tsx +2 -1
  88. package/blocks/block.schema.json +18 -0
  89. package/blocks/block.types.ts +17 -0
  90. package/blocks/campaigns/README.md +41 -11
  91. package/blocks/campaigns/block.json +105 -42
  92. package/blocks/campaigns/components/campaign-assets.tsx +17 -6
  93. package/blocks/campaigns/components/campaign-launch-step.tsx +114 -26
  94. package/blocks/campaigns/components/campaign-list.tsx +7 -3
  95. package/blocks/campaigns/components/campaign-metrics.tsx +1 -1
  96. package/blocks/campaigns/components/campaign-wizard.tsx +52 -14
  97. package/blocks/campaigns/components/campaigns-screen.tsx +267 -0
  98. package/blocks/campaigns/components/icp-detail.tsx +163 -0
  99. package/blocks/campaigns/components/icp-editor.tsx +22 -17
  100. package/blocks/campaigns/components/persona-detail.tsx +181 -0
  101. package/blocks/campaigns/components/persona-editor.tsx +19 -11
  102. package/blocks/campaigns/lib/campaigns-utils.ts +138 -5
  103. package/blocks/campaigns/recipes/attach-audience-and-launch.ts +16 -3
  104. package/blocks/campaigns/recipes/generate-ideas-and-create-campaign.ts +8 -4
  105. package/blocks/coach/README.md +10 -0
  106. package/blocks/coach/block.json +16 -1
  107. package/blocks/coach/components/call-scorecard.tsx +7 -7
  108. package/blocks/coach/components/coach-screen.tsx +222 -0
  109. package/blocks/company-intelligence/README.md +132 -0
  110. package/blocks/company-intelligence/block.json +318 -0
  111. package/blocks/company-intelligence/components/company-intelligence-screen.tsx +114 -0
  112. package/blocks/company-intelligence/components/company-intelligence-tab.tsx +88 -0
  113. package/blocks/company-intelligence/components/company-profile.tsx +68 -0
  114. package/blocks/company-intelligence/components/intelligence-sources.tsx +63 -0
  115. package/blocks/company-intelligence/components/report-detail.tsx +189 -0
  116. package/blocks/company-intelligence/components/research-reports.tsx +136 -0
  117. package/blocks/company-intelligence/components/research-run.tsx +161 -0
  118. package/blocks/company-intelligence/components/source-detail.tsx +117 -0
  119. package/blocks/company-intelligence/components/source-view.tsx +274 -0
  120. package/blocks/company-intelligence/components/wiki-document-detail.tsx +116 -0
  121. package/blocks/company-intelligence/components/wiki-documents.tsx +66 -0
  122. package/blocks/company-intelligence/hooks/use-intelligence.ts +173 -0
  123. package/blocks/company-intelligence/lib/intelligence-types.ts +230 -0
  124. package/blocks/company-intelligence/lib/safe-markdown.tsx +150 -0
  125. package/blocks/company-intelligence/recipes/read-competitors-and-news.ts +33 -0
  126. package/blocks/company-intelligence/recipes/research-your-website.ts +43 -0
  127. package/blocks/company-intelligence/recipes/write-the-research-reports.ts +54 -0
  128. package/blocks/copilot/README.md +13 -0
  129. package/blocks/copilot/block.json +14 -1
  130. package/blocks/copilot/components/copilot-memory.tsx +6 -2
  131. package/blocks/copilot/components/copilot-panel.tsx +14 -5
  132. package/blocks/copilot/components/copilot-screen.tsx +148 -0
  133. package/blocks/copilot/components/copilot-team-chat.tsx +13 -6
  134. package/blocks/crm/README.md +34 -0
  135. package/blocks/crm/block.json +107 -2
  136. package/blocks/crm/components/companies-screen.tsx +359 -0
  137. package/blocks/crm/components/company-detail.tsx +10 -8
  138. package/blocks/crm/components/company-table.tsx +11 -4
  139. package/blocks/crm/components/contact-detail.tsx +10 -7
  140. package/blocks/crm/components/contact-lookup-link.tsx +44 -0
  141. package/blocks/crm/components/contact-table.tsx +10 -3
  142. package/blocks/crm/components/contacts-screen.tsx +377 -0
  143. package/blocks/crm/components/dedupe-review.tsx +13 -6
  144. package/blocks/crm/components/import-wizard.tsx +7 -9
  145. package/blocks/crm/components/list-select.tsx +20 -0
  146. package/blocks/crm/components/notes-panel.tsx +4 -4
  147. package/blocks/crm/components/record-engagement-tab.tsx +103 -0
  148. package/blocks/crm/components/record-form.tsx +6 -4
  149. package/blocks/crm/components/task-list.tsx +4 -4
  150. package/blocks/crm/components/tasks-screen.tsx +399 -0
  151. package/blocks/crm/hooks/use-all-lists.ts +18 -0
  152. package/blocks/crm/hooks/use-custom-fields.ts +6 -1
  153. package/blocks/crm/hooks/use-page-query.ts +9 -1
  154. package/blocks/crm/lib/crm-types.ts +26 -2
  155. package/blocks/crm/lib/read-lists.ts +16 -0
  156. package/blocks/crm/lib/screen-parts.tsx +105 -0
  157. package/blocks/deals/README.md +24 -6
  158. package/blocks/deals/block.json +160 -5
  159. package/blocks/deals/components/close-deal-dialog.tsx +169 -0
  160. package/blocks/deals/components/deal-contacts-editor.tsx +134 -0
  161. package/blocks/deals/components/deal-detail.tsx +25 -13
  162. package/blocks/deals/components/deal-filters.tsx +65 -0
  163. package/blocks/deals/components/deal-line-items.tsx +120 -0
  164. package/blocks/deals/components/deal-notes-tab.tsx +97 -0
  165. package/blocks/deals/components/deal-related.tsx +31 -10
  166. package/blocks/deals/components/deal-tasks-tab.tsx +88 -0
  167. package/blocks/deals/components/deals-screen.tsx +66 -26
  168. package/blocks/deals/components/forecast-view.tsx +4 -4
  169. package/blocks/deals/components/pipeline-board.tsx +8 -6
  170. package/blocks/deals/components/pipeline-editor.tsx +132 -0
  171. package/blocks/deals/components/record-deals-tab.tsx +62 -0
  172. package/blocks/deals/components/stage-editor.tsx +5 -5
  173. package/blocks/deals/hooks/use-pipeline-deals.ts +21 -4
  174. package/blocks/deals/hooks/use-pipelines.ts +1 -1
  175. package/blocks/deals/lib/deal-extras.ts +156 -0
  176. package/blocks/dialer/README.md +45 -4
  177. package/blocks/dialer/block.json +84 -3
  178. package/blocks/dialer/components/call-contact-button.tsx +269 -0
  179. package/blocks/dialer/components/call-log-screen.tsx +208 -0
  180. package/blocks/dialer/components/call-log.tsx +23 -7
  181. package/blocks/dialer/components/call-queue.tsx +4 -4
  182. package/blocks/dialer/components/dialer-screen.tsx +361 -0
  183. package/blocks/dialer/components/dialer-session-detail.tsx +153 -0
  184. package/blocks/dialer/components/disposition-panel.tsx +1 -1
  185. package/blocks/dialer/components/live-calls-table.tsx +7 -3
  186. package/blocks/dialer/components/record-calls-tab.tsx +101 -0
  187. package/blocks/dialer/components/session-start-form.tsx +61 -12
  188. package/blocks/dialer/components/softphone.tsx +4 -2
  189. package/blocks/enrichment/README.md +29 -7
  190. package/blocks/enrichment/block.json +49 -9
  191. package/blocks/enrichment/components/bulk-enrich-panel.tsx +83 -29
  192. package/blocks/enrichment/components/email-verify-badge.tsx +31 -11
  193. package/blocks/enrichment/components/enrich-button.tsx +32 -9
  194. package/blocks/enrichment/components/enrichment-job-detail.tsx +78 -0
  195. package/blocks/enrichment/components/enrichment-screen.tsx +341 -0
  196. package/blocks/enrichment/components/waterfall-config.tsx +66 -17
  197. package/blocks/enrichment/lib/enrichment-types.ts +39 -0
  198. package/blocks/enrichment/recipes/bulk-enrich-and-poll.ts +15 -4
  199. package/blocks/enrichment/recipes/waterfall-pipeline.ts +3 -2
  200. package/blocks/forms/README.md +8 -0
  201. package/blocks/forms/block.json +139 -18
  202. package/blocks/forms/components/form-activity.tsx +71 -0
  203. package/blocks/forms/components/form-backfill.tsx +108 -0
  204. package/blocks/forms/components/form-builder.tsx +4 -2
  205. package/blocks/forms/components/form-embed.tsx +4 -2
  206. package/blocks/forms/components/form-groups.tsx +151 -0
  207. package/blocks/forms/components/form-mapping-editor.tsx +6 -9
  208. package/blocks/forms/components/form-route-history.tsx +72 -0
  209. package/blocks/forms/components/form-saved-views.tsx +81 -0
  210. package/blocks/forms/components/forms-screen.tsx +56 -19
  211. package/blocks/forms/components/more-rows.tsx +30 -0
  212. package/blocks/forms/components/submissions-export.tsx +67 -0
  213. package/blocks/forms/components/submissions-table.tsx +17 -6
  214. package/blocks/forms/lib/forms-extra.ts +67 -0
  215. package/blocks/inbox/README.md +32 -3
  216. package/blocks/inbox/block.json +29 -2
  217. package/blocks/inbox/components/inbox-list.tsx +7 -3
  218. package/blocks/inbox/components/inbox-screen.tsx +294 -27
  219. package/blocks/inbox/components/record-conversations-tab.tsx +154 -0
  220. package/blocks/inbox/components/reply-composer.tsx +65 -9
  221. package/blocks/inbox/components/tag-and-assign.tsx +4 -2
  222. package/blocks/inbox/components/thread-badge.tsx +2 -2
  223. package/blocks/inbox/components/thread-view.tsx +1 -1
  224. package/blocks/inbox/hooks/use-inbox-thread.ts +1 -1
  225. package/blocks/inbox/hooks/use-inbox-threads.ts +1 -0
  226. package/blocks/inbox/lib/inbox-types.ts +47 -1
  227. package/blocks/inbox/recipes/01-triage-and-reply.ts +12 -2
  228. package/blocks/integrations/README.md +63 -1
  229. package/blocks/integrations/block.json +234 -15
  230. package/blocks/integrations/components/ad-accounts.tsx +82 -0
  231. package/blocks/integrations/components/connection-health.tsx +59 -0
  232. package/blocks/integrations/components/crm-detail.tsx +119 -0
  233. package/blocks/integrations/components/crm-records.tsx +103 -0
  234. package/blocks/integrations/components/field-mappings.tsx +61 -0
  235. package/blocks/integrations/components/integration-list.tsx +13 -8
  236. package/blocks/integrations/components/integrations-screen.tsx +152 -0
  237. package/blocks/integrations/components/migration-panel.tsx +133 -0
  238. package/blocks/integrations/components/sugarcrm-connect.tsx +95 -0
  239. package/blocks/integrations/components/sync-status.tsx +11 -9
  240. package/blocks/integrations/components/sync-triggers.tsx +134 -0
  241. package/blocks/integrations/components/webhook-detail.tsx +179 -0
  242. package/blocks/integrations/components/webhook-manager.tsx +43 -25
  243. package/blocks/integrations/components/workspace-tools.tsx +127 -0
  244. package/blocks/integrations/lib/crm-utils.ts +39 -0
  245. package/blocks/integrations/lib/facts.tsx +13 -0
  246. package/blocks/integrations/lib/integrations-utils.ts +11 -1
  247. package/blocks/integrations/lib/load-more.tsx +141 -0
  248. package/blocks/intent/README.md +14 -0
  249. package/blocks/intent/block.json +27 -1
  250. package/blocks/intent/components/account-intent-score.tsx +5 -5
  251. package/blocks/intent/components/intent-feed.tsx +13 -10
  252. package/blocks/intent/components/intent-keyword-manager.tsx +16 -12
  253. package/blocks/intent/components/intent-screen.tsx +265 -0
  254. package/blocks/intent/components/keyword-detail.tsx +124 -0
  255. package/blocks/intent/lib/intent-utils.ts +4 -4
  256. package/blocks/lifecycle/block.json +13 -8
  257. package/blocks/lifecycle/components/account-related.tsx +8 -1
  258. package/blocks/lifecycle/components/churn-list.tsx +5 -2
  259. package/blocks/lifecycle/components/customer-table.tsx +1 -1
  260. package/blocks/lifecycle/components/lifecycle-board.tsx +3 -1
  261. package/blocks/lifecycle/components/lifecycle-screen.tsx +3 -1
  262. package/blocks/lifecycle/lib/lifecycle.ts +1 -1
  263. package/blocks/lists/README.md +20 -1
  264. package/blocks/lists/block.json +69 -3
  265. package/blocks/lists/components/add-company-people-to-list-button.tsx +73 -0
  266. package/blocks/lists/components/add-to-list-button.tsx +20 -9
  267. package/blocks/lists/components/list-picker.tsx +17 -3
  268. package/blocks/lists/components/list-table.tsx +12 -6
  269. package/blocks/lists/components/lists-screen.tsx +346 -0
  270. package/blocks/lists/components/record-lists-tab.tsx +99 -0
  271. package/blocks/lists/components/suppression-manager.tsx +33 -8
  272. package/blocks/lists/components/suppressions-screen.tsx +264 -0
  273. package/blocks/mailboxes/README.md +17 -0
  274. package/blocks/mailboxes/block.json +69 -17
  275. package/blocks/mailboxes/components/connect-mailbox.tsx +32 -21
  276. package/blocks/mailboxes/components/domain-detail.tsx +148 -0
  277. package/blocks/mailboxes/components/domain-purchase.tsx +20 -14
  278. package/blocks/mailboxes/components/mailbox-detail.tsx +157 -0
  279. package/blocks/mailboxes/components/mailbox-list.tsx +8 -3
  280. package/blocks/mailboxes/components/mailboxes-screen.tsx +228 -0
  281. package/blocks/mailboxes/components/warmup-health.tsx +24 -22
  282. package/blocks/mailboxes/lib/mailboxes-utils.ts +26 -5
  283. package/blocks/mailboxes/lib/use-provider-domains.ts +23 -0
  284. package/blocks/newsletter/README.md +12 -0
  285. package/blocks/newsletter/block.json +157 -24
  286. package/blocks/newsletter/components/issue-scheduler.tsx +4 -3
  287. package/blocks/newsletter/components/issue-versions.tsx +93 -0
  288. package/blocks/newsletter/components/more-rows.tsx +30 -0
  289. package/blocks/newsletter/components/newsletter-editor.tsx +1 -1
  290. package/blocks/newsletter/components/newsletter-list-syncs.tsx +121 -0
  291. package/blocks/newsletter/components/newsletter-screen.tsx +39 -14
  292. package/blocks/newsletter/components/newsletter-settings.tsx +211 -0
  293. package/blocks/newsletter/components/newsletter-stats.tsx +2 -2
  294. package/blocks/newsletter/components/newsletter-templates.tsx +133 -0
  295. package/blocks/newsletter/components/subscriber-table.tsx +5 -7
  296. package/blocks/newsletter/components/subscriber-timeline.tsx +65 -0
  297. package/blocks/newsletter/lib/newsletter-extra.ts +60 -0
  298. package/blocks/nurture/block.json +28 -14
  299. package/blocks/nurture/components/nurture-builder.tsx +13 -3
  300. package/blocks/nurture/components/nurture-enroll.tsx +12 -10
  301. package/blocks/nurture/components/nurture-form.tsx +27 -10
  302. package/blocks/nurture/components/nurture-screen.tsx +26 -11
  303. package/blocks/nurture/components/nurture-stats.tsx +5 -4
  304. package/blocks/nurture/lib/nurture-types.ts +1 -1
  305. package/blocks/objects/README.md +18 -1
  306. package/blocks/objects/block.json +42 -21
  307. package/blocks/objects/components/attribute-field-input.tsx +14 -1
  308. package/blocks/objects/components/object-not-found.tsx +3 -1
  309. package/blocks/objects/components/object-record-detail.tsx +10 -2
  310. package/blocks/objects/components/object-schema-editor.tsx +4 -2
  311. package/blocks/objects/components/object-table.tsx +13 -3
  312. package/blocks/objects/components/objects-screen.tsx +147 -0
  313. package/blocks/objects/components/record-roles-panel.tsx +15 -5
  314. package/blocks/objects/lib/object-types.ts +1 -1
  315. package/blocks/pages/README.md +14 -0
  316. package/blocks/pages/block.json +140 -23
  317. package/blocks/pages/components/brand-kit-editor.tsx +5 -2
  318. package/blocks/pages/components/content-library.tsx +9 -4
  319. package/blocks/pages/components/more-rows.tsx +30 -0
  320. package/blocks/pages/components/page-ai-tools.tsx +196 -0
  321. package/blocks/pages/components/page-analytics.tsx +176 -0
  322. package/blocks/pages/components/page-clone.tsx +99 -0
  323. package/blocks/pages/components/page-domains.tsx +167 -0
  324. package/blocks/pages/components/page-editor.tsx +1 -1
  325. package/blocks/pages/components/page-generation-status.tsx +48 -0
  326. package/blocks/pages/components/page-list.tsx +2 -1
  327. package/blocks/pages/components/page-tracking.tsx +137 -0
  328. package/blocks/pages/components/pages-screen.tsx +57 -16
  329. package/blocks/pages/components/seo-report.tsx +6 -1
  330. package/blocks/pages/lib/studio.ts +7 -0
  331. package/blocks/phone-numbers/README.md +74 -0
  332. package/blocks/phone-numbers/block.json +262 -0
  333. package/blocks/phone-numbers/components/a2p-registration.tsx +230 -0
  334. package/blocks/phone-numbers/components/assign-number.tsx +104 -0
  335. package/blocks/phone-numbers/components/number-search.tsx +239 -0
  336. package/blocks/phone-numbers/components/number-settings.tsx +134 -0
  337. package/blocks/phone-numbers/components/number-usage.tsx +97 -0
  338. package/blocks/phone-numbers/components/phone-number-detail.tsx +84 -0
  339. package/blocks/phone-numbers/components/phone-number-list.tsx +110 -0
  340. package/blocks/phone-numbers/components/phone-numbers-screen.tsx +201 -0
  341. package/blocks/phone-numbers/components/register-owned-number.tsx +98 -0
  342. package/blocks/phone-numbers/components/release-number.tsx +126 -0
  343. package/blocks/phone-numbers/hooks/use-phone-numbers.ts +58 -0
  344. package/blocks/phone-numbers/lib/phone-numbers-utils.ts +202 -0
  345. package/blocks/phone-numbers/recipes/01-search-and-buy-number.ts +49 -0
  346. package/blocks/phone-numbers/recipes/02-assign-number-to-rep.ts +25 -0
  347. package/blocks/phone-numbers/recipes/03-audit-numbers.ts +36 -0
  348. package/blocks/phone-numbers/recipes/04-register-text-messaging.ts +39 -0
  349. package/blocks/pickers/README.md +23 -0
  350. package/blocks/pickers/block.json +103 -0
  351. package/blocks/pickers/components/company-picker.tsx +90 -0
  352. package/blocks/pickers/components/contact-picker.tsx +131 -0
  353. package/blocks/pickers/components/member-picker.tsx +99 -0
  354. package/blocks/pickers/components/search-picker.tsx +98 -0
  355. package/blocks/pickers/hooks/use-current-member.ts +104 -0
  356. package/blocks/pickers/hooks/use-picker-pages.ts +73 -0
  357. package/blocks/pickers/lib/use-debounced.ts +13 -0
  358. package/blocks/quotes/README.md +13 -0
  359. package/blocks/quotes/block.json +65 -13
  360. package/blocks/quotes/components/create-quote-from-deal.tsx +48 -0
  361. package/blocks/quotes/components/product-picker.tsx +3 -1
  362. package/blocks/quotes/components/quote-builder.tsx +1 -1
  363. package/blocks/quotes/components/quote-lifecycle-actions.tsx +146 -0
  364. package/blocks/quotes/components/quote-list.tsx +5 -3
  365. package/blocks/quotes/components/quote-related.tsx +8 -4
  366. package/blocks/quotes/components/quote-viewer.tsx +7 -2
  367. package/blocks/quotes/components/record-quotes-tab.tsx +90 -0
  368. package/blocks/radar/README.md +10 -0
  369. package/blocks/radar/block.json +41 -1
  370. package/blocks/radar/components/competitor-battle-card.tsx +1 -1
  371. package/blocks/radar/components/competitor-detail.tsx +117 -0
  372. package/blocks/radar/components/competitor-tracker.tsx +3 -1
  373. package/blocks/radar/components/radar-overview.tsx +4 -4
  374. package/blocks/radar/components/radar-report.tsx +4 -2
  375. package/blocks/radar/components/radar-screen.tsx +214 -0
  376. package/blocks/radar/components/report-detail.tsx +104 -0
  377. package/blocks/search/README.md +10 -0
  378. package/blocks/search/block.json +16 -1
  379. package/blocks/search/components/filter-builder.tsx +3 -3
  380. package/blocks/search/components/prospect-results.tsx +5 -3
  381. package/blocks/search/components/prospect-search-screen.tsx +235 -0
  382. package/blocks/search/components/saved-searches.tsx +4 -1
  383. package/blocks/search/hooks/use-filter-options.ts +20 -6
  384. package/blocks/search/lib/search-types.ts +2 -0
  385. package/blocks/sequencer/README.md +55 -9
  386. package/blocks/sequencer/block.json +126 -19
  387. package/blocks/sequencer/components/add-to-sequence-button.tsx +82 -0
  388. package/blocks/sequencer/components/enroll-dialog.tsx +11 -5
  389. package/blocks/sequencer/components/record-sequences-tab.tsx +126 -0
  390. package/blocks/sequencer/components/sequence-builder.tsx +224 -60
  391. package/blocks/sequencer/components/sequence-detail.tsx +261 -0
  392. package/blocks/sequencer/components/sequence-enrollments.tsx +116 -0
  393. package/blocks/sequencer/components/sequence-list.tsx +34 -9
  394. package/blocks/sequencer/components/sequence-stats.tsx +11 -10
  395. package/blocks/sequencer/components/sequence-steps-panel.tsx +103 -0
  396. package/blocks/sequencer/components/sequences-screen.tsx +162 -0
  397. package/blocks/sequencer/components/step-editor.tsx +14 -12
  398. package/blocks/sequencer/lib/sequencer-utils.ts +133 -10
  399. package/blocks/sequencer/recipes/create-multichannel-sequence.ts +33 -5
  400. package/blocks/sequencer/recipes/launch-and-enroll.ts +19 -2
  401. package/blocks/social-ads/README.md +19 -0
  402. package/blocks/social-ads/block.json +233 -1
  403. package/blocks/social-ads/components/ad-campaign-list.tsx +9 -5
  404. package/blocks/social-ads/components/ads-screen.tsx +152 -0
  405. package/blocks/social-ads/components/audience-sync-detail.tsx +194 -0
  406. package/blocks/social-ads/components/audience-sync.tsx +17 -9
  407. package/blocks/social-ads/components/campaign-ads.tsx +166 -0
  408. package/blocks/social-ads/components/campaign-detail.tsx +138 -0
  409. package/blocks/social-ads/components/campaign-editor.tsx +134 -0
  410. package/blocks/social-ads/components/creative-concepts.tsx +74 -0
  411. package/blocks/social-ads/components/creative-detail.tsx +155 -0
  412. package/blocks/social-ads/components/creative-gallery.tsx +35 -7
  413. package/blocks/social-ads/components/creative-revisions.tsx +57 -0
  414. package/blocks/social-ads/components/creative-tools.tsx +176 -0
  415. package/blocks/social-ads/components/post-composer.tsx +7 -3
  416. package/blocks/social-ads/components/post-detail.tsx +163 -0
  417. package/blocks/social-ads/components/social-ideas.tsx +64 -0
  418. package/blocks/social-ads/components/social-performance.tsx +80 -0
  419. package/blocks/social-ads/components/social-post-list.tsx +11 -3
  420. package/blocks/social-ads/components/social-screen.tsx +187 -0
  421. package/blocks/social-ads/lib/ads-extra.ts +67 -0
  422. package/blocks/surveys/README.md +91 -0
  423. package/blocks/surveys/block.json +299 -0
  424. package/blocks/surveys/components/account-nps.tsx +69 -0
  425. package/blocks/surveys/components/contact-survey-history.tsx +52 -0
  426. package/blocks/surveys/components/org-summary.tsx +82 -0
  427. package/blocks/surveys/components/sending-domains.tsx +113 -0
  428. package/blocks/surveys/components/survey-form.tsx +126 -0
  429. package/blocks/surveys/components/survey-responses.tsx +145 -0
  430. package/blocks/surveys/components/survey-results.tsx +72 -0
  431. package/blocks/surveys/components/survey-send-history.tsx +58 -0
  432. package/blocks/surveys/components/survey-send.tsx +162 -0
  433. package/blocks/surveys/components/survey-triggers.tsx +166 -0
  434. package/blocks/surveys/components/surveys-screen.tsx +234 -0
  435. package/blocks/surveys/lib/surveys-types.ts +228 -0
  436. package/blocks/surveys/recipes/create-an-nps-survey.ts +22 -0
  437. package/blocks/surveys/recipes/send-a-survey-and-follow-it.ts +27 -0
  438. package/blocks/surveys/recipes/survey-score-report.ts +27 -0
  439. package/blocks/visitors/README.md +10 -0
  440. package/blocks/visitors/block.json +25 -1
  441. package/blocks/visitors/components/snippet-install.tsx +21 -10
  442. package/blocks/visitors/components/traffic-chart.tsx +4 -4
  443. package/blocks/visitors/components/visitor-company-card.tsx +26 -16
  444. package/blocks/visitors/components/visitor-detail.tsx +105 -0
  445. package/blocks/visitors/components/visitor-feed.tsx +16 -7
  446. package/blocks/visitors/components/visitors-screen.tsx +166 -0
  447. package/blocks/webchat/README.md +10 -0
  448. package/blocks/webchat/block.json +21 -7
  449. package/blocks/webchat/components/chat-widget-config.tsx +8 -5
  450. package/blocks/webchat/components/conversation-list.tsx +8 -4
  451. package/blocks/webchat/components/webchat-screen.tsx +245 -0
  452. package/blocks/workbench/README.md +11 -0
  453. package/blocks/workbench/block.json +48 -1
  454. package/blocks/workbench/components/column-recipe-editor.tsx +5 -3
  455. package/blocks/workbench/components/run-progress.tsx +1 -1
  456. package/blocks/workbench/components/workbench-grid.tsx +10 -4
  457. package/blocks/workbench/components/workbench-row-detail.tsx +104 -0
  458. package/blocks/workbench/components/workbench-screen.tsx +202 -0
  459. package/blocks/workbench/components/workbench-sources.tsx +194 -0
  460. package/blocks/workbench/components/workbench-table-list.tsx +14 -2
  461. package/blocks/workflows/README.md +13 -0
  462. package/blocks/workflows/block.json +28 -9
  463. package/blocks/workflows/components/run-history.tsx +31 -9
  464. package/blocks/workflows/components/trigger-config.tsx +3 -1
  465. package/blocks/workflows/components/workflow-editor.tsx +4 -2
  466. package/blocks/workflows/components/workflow-list.tsx +13 -6
  467. package/blocks/workflows/components/workflows-screen.tsx +193 -0
  468. package/dist/cli.js +3109 -1977
  469. package/dist/errors.d.mts +34 -0
  470. package/dist/errors.d.ts +34 -0
  471. package/dist/errors.js +46 -0
  472. package/dist/errors.js.map +1 -0
  473. package/dist/errors.mjs +21 -0
  474. package/dist/errors.mjs.map +1 -0
  475. package/dist/index.browser.js +11 -5
  476. package/dist/index.browser.js.map +1 -1
  477. package/dist/index.browser.mjs +11 -5
  478. package/dist/index.browser.mjs.map +1 -1
  479. package/dist/index.d.mts +164 -25
  480. package/dist/index.d.ts +164 -25
  481. package/dist/index.js +11 -5
  482. package/dist/index.js.map +1 -1
  483. package/dist/index.mjs +11 -5
  484. package/dist/index.mjs.map +1 -1
  485. package/dist/react.browser.js +10 -4
  486. package/dist/react.browser.js.map +1 -1
  487. package/dist/react.browser.mjs +10 -4
  488. package/dist/react.browser.mjs.map +1 -1
  489. package/dist/react.d.mts +142 -5
  490. package/dist/react.d.ts +142 -5
  491. package/dist/react.js +10 -4
  492. package/dist/react.js.map +1 -1
  493. package/dist/react.mjs +10 -4
  494. package/dist/react.mjs.map +1 -1
  495. package/dist/types/blocks/add.d.ts +11 -4
  496. package/dist/types/blocks/brand.d.ts +122 -0
  497. package/dist/types/blocks/compose.d.ts +53 -0
  498. package/dist/types/blocks/create.d.ts +27 -20
  499. package/dist/types/blocks/doctor.d.ts +6 -1
  500. package/dist/types/blocks/flows.d.ts +7 -1
  501. package/dist/types/blocks/navfile.d.ts +35 -0
  502. package/dist/types/blocks/orgBrand.d.ts +34 -0
  503. package/dist/types/blocks/paths.d.ts +4 -0
  504. package/dist/types/blocks/prefixes.d.ts +37 -0
  505. package/dist/types/blocks/registry.d.ts +17 -0
  506. package/dist/types/blocks/screens.d.ts +53 -0
  507. package/dist/types/cli.d.ts +5 -0
  508. package/dist/types/errors.d.ts +33 -0
  509. package/dist/types/http.d.ts +2 -18
  510. package/dist/types/version.d.ts +2 -2
  511. package/docs/agents.md +15 -4
  512. package/docs/api/README.md +2 -2
  513. package/docs/api/by-path.md +1 -0
  514. package/docs/api/desk.d.ts +98 -2
  515. package/docs/api/desk.md +123 -1
  516. package/docs/api/inbox.d.ts +10 -2
  517. package/docs/api/inbox.md +10 -2
  518. package/docs/api/seo.d.ts +19 -1
  519. package/docs/api/seo.md +24 -1
  520. package/package.json +16 -2
  521. package/stacks/6sense/pages/companies.tsx.tmpl +21 -0
  522. package/stacks/6sense/pages/contacts.tsx.tmpl +19 -0
  523. package/stacks/6sense/pages/tasks.tsx.tmpl +19 -0
  524. package/stacks/6sense.json +55 -17
  525. package/stacks/apollo/pages/calls.tsx.tmpl +23 -0
  526. package/stacks/apollo/pages/companies.tsx.tmpl +33 -0
  527. package/stacks/apollo/pages/contacts.tsx.tmpl +51 -0
  528. package/stacks/apollo/pages/deals.tsx.tmpl +17 -0
  529. package/stacks/apollo/pages/inbox-contact.tsx.tmpl +13 -0
  530. package/stacks/apollo/pages/lists.tsx.tmpl +12 -0
  531. package/stacks/apollo/pages/meetings.tsx.tmpl +13 -0
  532. package/stacks/apollo/pages/sequences.tsx.tmpl +12 -0
  533. package/stacks/apollo/pages/tasks.tsx.tmpl +20 -0
  534. package/stacks/apollo.json +147 -37
  535. package/stacks/calendly/pages/companies.tsx.tmpl +19 -0
  536. package/stacks/calendly/pages/contacts.tsx.tmpl +21 -0
  537. package/stacks/calendly/pages/meetings.tsx.tmpl +13 -0
  538. package/stacks/calendly/pages/tasks.tsx.tmpl +19 -0
  539. package/stacks/calendly.json +64 -0
  540. package/stacks/clay/pages/companies.tsx.tmpl +31 -0
  541. package/stacks/clay/pages/contacts.tsx.tmpl +31 -0
  542. package/stacks/clay/pages/lists.tsx.tmpl +12 -0
  543. package/stacks/clay/pages/tasks.tsx.tmpl +19 -0
  544. package/stacks/clay.json +73 -27
  545. package/stacks/gong/pages/calls.tsx.tmpl +23 -0
  546. package/stacks/gong/pages/companies.tsx.tmpl +22 -0
  547. package/stacks/gong/pages/contacts.tsx.tmpl +32 -0
  548. package/stacks/gong/pages/lists.tsx.tmpl +12 -0
  549. package/stacks/gong/pages/meetings.tsx.tmpl +13 -0
  550. package/stacks/gong/pages/tasks.tsx.tmpl +19 -0
  551. package/stacks/gong.json +98 -35
  552. package/stacks/hootsuite/pages/companies.tsx.tmpl +22 -0
  553. package/stacks/hootsuite/pages/contacts.tsx.tmpl +28 -0
  554. package/stacks/hootsuite/pages/lists.tsx.tmpl +12 -0
  555. package/stacks/hootsuite/pages/tasks.tsx.tmpl +19 -0
  556. package/stacks/hootsuite.json +104 -0
  557. package/stacks/hubspot/pages/companies.tsx.tmpl +26 -0
  558. package/stacks/hubspot/pages/contacts.tsx.tmpl +45 -0
  559. package/stacks/hubspot/pages/deals.tsx.tmpl +20 -0
  560. package/stacks/hubspot/pages/inbox.tsx.tmpl +103 -0
  561. package/stacks/hubspot/pages/lifecycle.tsx.tmpl +23 -0
  562. package/stacks/hubspot/pages/lists.tsx.tmpl +12 -0
  563. package/stacks/hubspot/pages/meetings.tsx.tmpl +13 -0
  564. package/stacks/hubspot/pages/quotes.tsx.tmpl +11 -0
  565. package/stacks/hubspot/pages/sequences.tsx.tmpl +12 -0
  566. package/stacks/hubspot/pages/tasks.tsx.tmpl +20 -0
  567. package/stacks/hubspot.json +181 -64
  568. package/stacks/intercom/pages/companies.tsx.tmpl +19 -0
  569. package/stacks/intercom/pages/contacts.tsx.tmpl +21 -0
  570. package/stacks/intercom/pages/inbox-contact.tsx.tmpl +13 -0
  571. package/stacks/intercom/pages/tasks.tsx.tmpl +19 -0
  572. package/stacks/intercom.json +52 -20
  573. package/stacks/mailchimp/pages/companies.tsx.tmpl +22 -0
  574. package/stacks/mailchimp/pages/contacts.tsx.tmpl +28 -0
  575. package/stacks/mailchimp/pages/lists.tsx.tmpl +12 -0
  576. package/stacks/mailchimp/pages/tasks.tsx.tmpl +19 -0
  577. package/stacks/mailchimp.json +68 -34
  578. package/stacks/outreach/pages/calls.tsx.tmpl +23 -0
  579. package/stacks/outreach/pages/companies.tsx.tmpl +22 -0
  580. package/stacks/outreach/pages/contacts.tsx.tmpl +46 -0
  581. package/stacks/outreach/pages/inbox-contact.tsx.tmpl +13 -0
  582. package/stacks/outreach/pages/lists.tsx.tmpl +12 -0
  583. package/stacks/outreach/pages/meetings.tsx.tmpl +13 -0
  584. package/stacks/outreach/pages/sequences.tsx.tmpl +12 -0
  585. package/stacks/outreach/pages/tasks.tsx.tmpl +19 -0
  586. package/stacks/outreach.json +106 -25
  587. package/stacks/pipedrive/pages/companies.tsx.tmpl +23 -0
  588. package/stacks/pipedrive/pages/contacts.tsx.tmpl +27 -0
  589. package/stacks/pipedrive/pages/deals.tsx.tmpl +20 -0
  590. package/stacks/pipedrive/pages/inbox.tsx.tmpl +103 -0
  591. package/stacks/pipedrive/pages/meetings.tsx.tmpl +13 -0
  592. package/stacks/pipedrive/pages/quotes.tsx.tmpl +11 -0
  593. package/stacks/pipedrive/pages/tasks.tsx.tmpl +20 -0
  594. package/stacks/pipedrive.json +117 -0
  595. package/stacks/salesforce/pages/companies.tsx.tmpl +26 -0
  596. package/stacks/salesforce/pages/contacts.tsx.tmpl +32 -0
  597. package/stacks/salesforce/pages/deals.tsx.tmpl +20 -0
  598. package/stacks/salesforce/pages/lifecycle.tsx.tmpl +23 -0
  599. package/stacks/salesforce/pages/lists.tsx.tmpl +12 -0
  600. package/stacks/salesforce/pages/quotes.tsx.tmpl +11 -0
  601. package/stacks/salesforce/pages/tasks.tsx.tmpl +20 -0
  602. package/stacks/salesforce.json +85 -31
  603. package/stacks/zoominfo/pages/companies.tsx.tmpl +31 -0
  604. package/stacks/zoominfo/pages/contacts.tsx.tmpl +31 -0
  605. package/stacks/zoominfo/pages/lists.tsx.tmpl +12 -0
  606. package/stacks/zoominfo/pages/tasks.tsx.tmpl +19 -0
  607. package/stacks/zoominfo.json +115 -0
  608. package/styles/styles.css +1 -1
  609. package/templates/next-app/README.md.tmpl +40 -9
  610. package/templates/next-app/app/globals.css.tmpl +349 -64
  611. package/templates/next-app/app/layout.tsx.tmpl +7 -2
  612. package/templates/next-app/components/app-shell.tsx.tmpl +104 -88
  613. package/templates/next-app/components/shell/quick-jump.tsx.tmpl +4 -0
  614. package/templates/next-app/dot-gitignore.tmpl +2 -0
  615. package/templates/next-app/package.json.tmpl +1 -1
@@ -0,0 +1,222 @@
1
+ "use client";
2
+
3
+ /**
4
+ * CoachScreen: the finished sales coach page. Tabs: Practice calls (graded calls newest first with a score and the first
5
+ * tip; open one for the full scorecard, recording and transcript, deep link `?id=`), Leaderboard (reps ranked by score) and
6
+ * Real calls (the rep's dialer calls, only when a rep email is known). Stats summarise the loaded calls: how many, the
7
+ * average and best score, and the stage reps miss most.
8
+ *
9
+ * Flows: browse and open calls; load a signed recording (CallScorecard); delete a call (destructive, ConfirmSpendDialog;
10
+ * hide with allowDelete={false}); create a practice call row (write; the live practice conversation itself runs in the
11
+ * graph8 app, so the form links out); managers type a rep's email to read that rep's calls (needs a manager key, a 403 is shown).
12
+ *
13
+ * SDK operations (through the composed parts): GET /sales-coach/calls, GET /sales-coach/leaderboard, POST /sales-coach/calls,
14
+ * and CallScorecard's getCall, getCallTranscript, getCallAudioUrl and deleteCall; GET /voice/dialer/calls via the dialer block.
15
+ */
16
+ import { useEffect, useMemo, useRef, useState, type ReactNode } from "react";
17
+ import { GraduationCap } from "lucide-react";
18
+ import { Button, Input, Label, Skeleton, Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@graph8/sdk/ui";
19
+ import { ApiError } from "@/g8/components/api-error";
20
+ import { EmptyState } from "@/g8/components/empty-state";
21
+ import { DetailPanel } from "@/g8/components/screen/detail-panel";
22
+ import { EntityAvatar } from "@/g8/components/screen/entity-avatar";
23
+ import { FormSheet } from "@/g8/components/screen/form-sheet";
24
+ import { ScreenLayout } from "@/g8/components/screen/screen-layout";
25
+ import { SplitView } from "@/g8/components/screen/split-view";
26
+ import { StatusPill } from "@/g8/components/screen/status-pill";
27
+ import { Toolbar } from "@/g8/components/screen/toolbar";
28
+ import { useG8Mutation } from "@/g8/hooks/use-g8-mutation";
29
+ import { useG8Query } from "@/g8/hooks/use-g8-query";
30
+ import { useUrlState } from "@/g8/hooks/use-url-state";
31
+ import { g8Get, g8Post } from "@/g8/lib/g8-client";
32
+ import { CallHistory } from "@/g8/dialer/components/call-log-screen";
33
+ import { avgOf, listOf, scorecardOf } from "../lib/coach-types";
34
+ import type { CoachCall, LeaderboardRow } from "../lib/coach-types";
35
+ import { CallScorecard } from "./call-scorecard";
36
+ import { useBrand } from "@/g8/hooks/use-brand";
37
+
38
+ export interface CoachScreenProps {
39
+ /** Whose practice calls. Omit for the key owner's own; managers may type another rep's email. */
40
+ userEmail?: string;
41
+ /** Show the "New practice call" button (creates the row only). Default true when no rep email is set. */
42
+ allowCreate?: boolean;
43
+ allowDelete?: boolean;
44
+ toolbarActions?: ReactNode;
45
+ renderRowActions?: (call: CoachCall) => ReactNode;
46
+ renderDetailActions?: (call: CoachCall) => ReactNode;
47
+ extraDetailTabs?: Array<{ id: string; label: string; render: (call: CoachCall) => ReactNode }>;
48
+ className?: string;
49
+ }
50
+
51
+ function useDebounced<T>(value: T, ms = 400): T {
52
+ const [v, setV] = useState(value);
53
+ useEffect(() => {
54
+ const t = setTimeout(() => setV(value), ms);
55
+ return () => clearTimeout(t);
56
+ }, [value, ms]);
57
+ return v;
58
+ }
59
+
60
+ const scoreTone = (pct: number | null | undefined) => (pct == null ? "neutral" : pct >= 75 ? "positive" : pct >= 50 ? "warning" : "negative");
61
+ const EMPTY_FORM = { call_mode: "assisted" as "assisted" | "compete", prospect_name: "", prospect_company: "", persona_type: "" };
62
+
63
+ function weakestStage(rows: CoachCall[]): string | null {
64
+ const sums = new Map<string, { total: number; n: number }>();
65
+ for (const c of rows) for (const s of scorecardOf(c)?.stages ?? []) if (s.pct != null) sums.set(s.label, { total: (sums.get(s.label)?.total ?? 0) + s.pct, n: (sums.get(s.label)?.n ?? 0) + 1 });
66
+ const ranked = [...sums].map(([k, v]) => [k, v.total / v.n] as const).sort((a, b) => a[1] - b[1]);
67
+ return ranked[0]?.[0] ?? null;
68
+ }
69
+
70
+ function NewCallSheet({ open, onOpenChange, onCreated }: { open: boolean; onOpenChange: (o: boolean) => void; onCreated: () => void }) {
71
+ const brand = useBrand();
72
+ const [form, setForm] = useState(EMPTY_FORM);
73
+ const create = useG8Mutation(
74
+ () => g8Post("/sales-coach/calls", { call_mode: form.call_mode, prospect_name: form.prospect_name.trim() || undefined, prospect_company: form.prospect_company.trim() || undefined, persona_type: form.persona_type.trim() || undefined }),
75
+ { onSuccess: () => { setForm(EMPTY_FORM); onOpenChange(false); onCreated(); } },
76
+ );
77
+ const field = (id: string, text: string, key: "prospect_name" | "prospect_company" | "persona_type") => (
78
+ <div className="flex flex-col gap-1"><Label htmlFor={id}>{text}</Label><Input id={id} value={form[key]} onChange={(e) => setForm({ ...form, [key]: e.target.value })} /></div>
79
+ );
80
+ return (
81
+ <FormSheet
82
+ open={open}
83
+ onOpenChange={onOpenChange}
84
+ title="New practice call"
85
+ description={`This adds the call to your list. The live practice conversation runs in ${brand.linkLabel}.`}
86
+ footer={<><Button variant="ghost" onClick={() => onOpenChange(false)}>Cancel</Button><Button loading={create.loading} onClick={() => void create.mutate(undefined)}>Create call</Button></>}
87
+ >
88
+ <div className="grid gap-3">
89
+ {field("pc-name", "Prospect", "prospect_name")}
90
+ {field("pc-company", "Company", "prospect_company")}
91
+ {field("pc-persona", "Persona", "persona_type")}
92
+ <div className="flex flex-col gap-1"><Label htmlFor="pc-mode">Mode</Label>
93
+ <select id="pc-mode" className="h-9 rounded-md border border-border bg-background px-2 text-sm" value={form.call_mode} onChange={(e) => setForm({ ...form, call_mode: e.target.value as "assisted" | "compete" })}><option value="assisted">Training</option><option value="compete">Compete</option></select>
94
+ </div>
95
+ {create.error ? <ApiError error={create.error} title="Could not create the call" /> : null}
96
+ <a className="text-sm underline" href={brand.appUrl} target="_blank" rel="noreferrer">Practice in {brand.linkLabel}</a>
97
+ </div>
98
+ </FormSheet>
99
+ );
100
+ }
101
+
102
+ function Leaderboard({ enabled }: { enabled: boolean }) {
103
+ const board = useG8Query((signal) => g8Get("/sales-coach/leaderboard", undefined, { signal }), [], { enabled });
104
+ const ranked = [...listOf<LeaderboardRow>(board.data, "items")].sort((a, b) => b.score - a.score);
105
+ if (board.error) return <ApiError error={board.error} title="Could not load the leaderboard" onRetry={() => void board.refetch()} />;
106
+ if (board.loading && ranked.length === 0) return <Skeleton className="h-32 w-full" aria-label="Loading leaderboard" />;
107
+ if (ranked.length === 0) return <EmptyState title="Nobody on the board yet" description="Completed practice calls rank here." />;
108
+ return (
109
+ <Table>
110
+ <TableHeader><TableRow><TableHead className="w-12">#</TableHead><TableHead>Rep</TableHead><TableHead className="text-right">Calls</TableHead><TableHead className="text-right">Avg</TableHead><TableHead className="text-right">Total</TableHead></TableRow></TableHeader>
111
+ <TableBody>
112
+ {ranked.map((r, i) => (
113
+ <TableRow key={r.email} data-testid={`rank-${r.email}`}>
114
+ <TableCell>{i + 1}</TableCell>
115
+ <TableCell><span className="flex items-center gap-2"><EntityAvatar name={r.name || r.email} kind="person" size="sm" />{r.name}<span className="text-xs text-muted-foreground">{r.email}</span></span></TableCell>
116
+ <TableCell className="text-right">{r.calls}</TableCell><TableCell className="text-right">{avgOf(r)}</TableCell><TableCell className="text-right">{r.score}</TableCell>
117
+ </TableRow>
118
+ ))}
119
+ </TableBody>
120
+ </Table>
121
+ );
122
+ }
123
+
124
+ export function CoachScreen(props: CoachScreenProps) {
125
+ const brand = useBrand();
126
+ const { allowDelete, toolbarActions, renderRowActions, renderDetailActions, extraDetailTabs, className } = props;
127
+ const [tab, setTab] = useUrlState("tab", "calls");
128
+ const [openId, setOpenId] = useUrlState("id");
129
+ const [view, setView] = useUrlState("view");
130
+ const [typed, setTyped] = useState("");
131
+ const [shown, setShown] = useState(15);
132
+ const [creating, setCreating] = useState(false);
133
+ const typedEmail = useDebounced(typed.trim());
134
+ const email = props.userEmail || typedEmail || undefined;
135
+ const allowCreate = props.allowCreate ?? !email;
136
+
137
+ const calls = useG8Query((signal) => g8Get("/sales-coach/calls", { email }, { signal }), [email]);
138
+ // Another rep's calls are a different list: forget the selection and paging.
139
+ const lastEmail = useRef(email);
140
+ useEffect(() => {
141
+ if (lastEmail.current === email) return; // keep a deep-linked ?id= on first render
142
+ lastEmail.current = email;
143
+ setShown(15);
144
+ setOpenId(null);
145
+ }, [email]); // eslint-disable-line react-hooks/exhaustive-deps
146
+ const rows = listOf<CoachCall>(calls.data, "items");
147
+ const selected = openId ? rows.find((c) => c.id === openId) : undefined;
148
+ const cards = useMemo(() => rows.map((c) => scorecardOf(c)?.scorePct).filter((n): n is number => typeof n === "number"), [rows]);
149
+ const avg = cards.length ? Math.round(cards.reduce((a, b) => a + b, 0) / cards.length) : null;
150
+ const tabs = [{ id: "calls", label: "Practice calls", count: rows.length || undefined }, { id: "board", label: "Leaderboard" }, ...(email ? [{ id: "real", label: "Real calls" }] : [])];
151
+ const active = tabs.some((t) => t.id === tab) ? tab : "calls";
152
+
153
+ const list = (
154
+ <div className="space-y-2">
155
+ {calls.error ? <ApiError error={calls.error} title="Could not load practice calls" onRetry={() => void calls.refetch()} /> : null}
156
+ {calls.loading && rows.length === 0 ? Array.from({ length: 3 }, (_, i) => <Skeleton key={i} className="h-16 w-full" />) : null}
157
+ <ul className="flex flex-col gap-2" data-testid="feed">
158
+ {rows.slice(0, shown).map((c) => {
159
+ const card = scorecardOf(c);
160
+ const tip = card?.improvements[0];
161
+ return (
162
+ <li key={c.id} className="flex items-start gap-1">
163
+ <button type="button" data-testid={`call-${c.id}`} onClick={() => setOpenId(c.id)} className={`min-w-0 flex-1 rounded-md border border-border p-3 text-left ${openId === c.id ? "bg-muted" : "hover:bg-muted/50"}`}>
164
+ <span className="flex items-center justify-between gap-2">
165
+ <span className="truncate font-medium">{c.prospect_name || "Practice call"}{c.prospect_company ? ` at ${c.prospect_company}` : ""}</span>
166
+ {card?.scorePct != null ? <StatusPill tone={scoreTone(card.scorePct)}>{`${Math.round(card.scorePct)}%`}</StatusPill> : <StatusPill tone="neutral">{c.call_status ?? "not graded"}</StatusPill>}
167
+ </span>
168
+ <span className="block text-xs text-muted-foreground">{c.date_of_call ? new Date(c.date_of_call).toLocaleDateString() : ""} {c.call_mode ?? ""}</span>
169
+ {tip ? <span className="mt-1 block text-sm">Work on: {tip}</span> : null}
170
+ </button>
171
+ {renderRowActions ? <div className="shrink-0 p-1">{renderRowActions(c)}</div> : null}
172
+ </li>
173
+ );
174
+ })}
175
+ </ul>
176
+ {!calls.loading && !calls.error && rows.length === 0 ? (
177
+ <EmptyState icon={<GraduationCap className="size-6" />} title="No practice calls yet" description={`Graded practice calls and what to work on next show up here. Practice calls run in ${brand.linkLabel}.`} action={allowCreate ? <Button size="sm" onClick={() => setCreating(true)}>New practice call</Button> : undefined} />
178
+ ) : null}
179
+ {rows.length > shown ? <Button variant="outline" size="sm" onClick={() => setShown(shown + 15)}>Show more</Button> : null}
180
+ </div>
181
+ );
182
+ const expanded = view === "full" && Boolean(openId);
183
+ const detail = openId ? (
184
+ <DetailPanel
185
+ title={selected?.prospect_name || "Practice call"}
186
+ subtitle={selected?.prospect_company ?? undefined}
187
+ actions={selected ? renderDetailActions?.(selected) : undefined}
188
+ onClose={() => { setOpenId(null); setView(null); }}
189
+ onExpand={expanded ? undefined : () => setView("full")}
190
+ onCollapse={expanded ? () => setView(null) : undefined}
191
+ tabs={[
192
+ { id: "scorecard", label: "Scorecard", content: <CallScorecard key={openId} callId={openId} allowDelete={allowDelete} onDeleted={() => { setOpenId(null); setView(null); void calls.refetch(); }} /> },
193
+ ...(selected ? (extraDetailTabs ?? []).map((t) => ({ id: t.id, label: t.label, content: t.render(selected) })) : []),
194
+ ]}
195
+ />
196
+ ) : null;
197
+
198
+ return (
199
+ <ScreenLayout
200
+ className={className}
201
+ title="Sales coach"
202
+ description="Scored practice calls, what to work on next, and how the team ranks."
203
+ icon={<GraduationCap className="size-5" />}
204
+ actions={<>{allowCreate ? <Button size="sm" onClick={() => setCreating(true)}>New practice call</Button> : null}{toolbarActions}</>}
205
+ tabs={tabs}
206
+ activeTab={active}
207
+ onTabChange={(id) => { setTab(id); setOpenId(null); setView(null); }}
208
+ stats={rows.length > 0 ? [
209
+ { label: "Calls loaded", value: rows.length },
210
+ { label: "Average score", value: avg != null ? `${avg}%` : "", tone: scoreTone(avg) },
211
+ { label: "Best score", value: cards.length ? `${Math.round(Math.max(...cards))}%` : "" },
212
+ { label: "Weakest stage", value: weakestStage(rows) ?? "", hint: "lowest average" },
213
+ ] : undefined}
214
+ toolbar={props.userEmail ? undefined : <Toolbar search={{ value: typed, onChange: setTyped, placeholder: "Rep email (managers)" }} />}
215
+ >
216
+ {active === "calls" ? <SplitView list={list} detail={detail} detailOpen={Boolean(openId)} onCloseDetail={() => { setOpenId(null); setView(null); }} expanded={expanded} onExpandedChange={(next) => setView(next ? "full" : null)} /> : null}
217
+ {active === "board" ? <Leaderboard enabled /> : null}
218
+ {active === "real" ? <CallHistory userEmail={email} idParam="call" /> : null}
219
+ <NewCallSheet open={creating} onOpenChange={setCreating} onCreated={() => void calls.refetch()} />
220
+ </ScreenLayout>
221
+ );
222
+ }
@@ -0,0 +1,132 @@
1
+ # company-intelligence
2
+
3
+ Research **your own website** and read what it found: the company profile, competitors, brand news, products, keywords,
4
+ audience questions and brand assets; the wiki documents written from that research; and the six market research reports
5
+ (review sentiment, competitive teardown, voice of customer, GTM channels, analyst and media, buyer psychology). Billable steps
6
+ (a research run, a document rewrite, writing a report) are confirmed with the number of things they touch; deleting and
7
+ resetting are confirmed as destructive.
8
+
9
+ **What this is not.** The company intelligence API researches the workspace's own website and is locked to it. It has **no
10
+ lookup for other companies**, no technographics, no org chart, no firmographics for a prospect and no AI briefing endpoint (see
11
+ "API gaps"). The screens say so instead of inventing data.
12
+
13
+ ## Screens
14
+
15
+ `CompanyIntelligenceScreen` (`components/company-intelligence-screen.tsx`) is the finished page. Copy it as your route; no props are required.
16
+
17
+ ```tsx
18
+ import { CompanyIntelligenceScreen } from "@/g8/company-intelligence/components/company-intelligence-screen";
19
+ export default function Page() { return <CompanyIntelligenceScreen />; }
20
+ ```
21
+
22
+ Tabs (`?tab=`): **Overview** (start, follow and reset the research; the company profile), **Sources** (everything collected, and the sources that failed; open one with `?id=<type>` to read it and re-collect it), **Documents** (the wiki documents; `?id=` opens one to read or rewrite), **Reports** (the six reports and their workflow; `?id=` opens one). `&view=full` shows a detail as a full page.
23
+
24
+ Flows: research the website (confirmed; follows progress step by step), research again (`force`), reset the research (confirmed with the real record count), read each source (profile, competitors, news with sentiment, products, keywords, questions, trends, pages, brand assets), re-collect one source (confirmed), search and filter the wiki documents, read one as formatted text, rewrite one (confirmed), write one report or all six (confirmed with the count), retry a failed report, write the missing ones, stop a run, reset the workflow, read a report, edit its text (changed text only), approve it into the knowledge base and remove it again, read the model's recorded reasoning, write a report again, delete it. Optional props: `toolbarActions`, `renderDetailActions(record)`, `extraDetailTabs` (each `{ id, label, render(record) }`), where `record` is `{ kind: "source" | "document" | "report", id }`.
25
+
26
+ Parts you can mount alone: `ResearchRun`, `CompanyProfileCard`, `IntelligenceSources`, `SourceDetail`, `SourceView`, `WikiDocuments`, `WikiDocumentDetail`, `ResearchReports`, `ReportDetail`, and the CRM tab below.
27
+
28
+ ### On a CRM company page: `CompanyIntelligenceTab`
29
+
30
+ ```tsx
31
+ <CompaniesScreen
32
+ extraDetailTabs={[{ id: "intelligence", label: "Intelligence", render: (c) => <CompanyIntelligenceTab company={c} /> }]}
33
+ />
34
+ ```
35
+
36
+ The stacks that include both `crm` and this block (apollo, zoominfo, clay, 6sense) already mount it. It shows the full profile when the company on screen **is** your workspace's website, the competitor entry your research holds when it is one of the competitors the research found, and otherwise says plainly that there is nothing to show. It never invents data for other companies.
37
+
38
+ ## Install
39
+
40
+ ```
41
+ npx @graph8/sdk add company-intelligence
42
+ ```
43
+
44
+ Installs `foundation` first if missing. Everything lands under `g8/company-intelligence/`. Add `intelligence`, `global-context` and `research-reports` to the proxy allowlist (the installer does this from the block's operations).
45
+
46
+ ## Prerequisites (the human must do these)
47
+
48
+ | Where | What | How to verify |
49
+ |---|---|---|
50
+ | graph8 key | `knowledge:read`, `knowledge:run`, `knowledge:delete` (research, documents) and `campaigns:read`, `campaigns:write`, `campaigns:run`, `campaigns:delete` (research reports). | `g8.api.me.describeCurrentKey()` |
51
+ | Credits | Research runs, document rewrites and report writing spend credits. The API quotes no price and has no balance read. | The owner knows the balance. |
52
+ | The business | Which website is researched. The first run locks the workspace to it. | `GET /api/v1/intelligence/primary-website` shows `has_website: true`. |
53
+
54
+ ## The flow, in order (IDs passed between steps)
55
+
56
+ 1. **Target**: `getIntelligencePrimaryWebsite` -> `primary_website_url` (null before the first run). If null, `getIntelligenceOrgDomain` -> `company_domain` is only a **suggestion**; a person confirms it.
57
+ 2. **Research**: `analyzeWebsite({ website_url, force? })` behind `ConfirmSpendDialog` -> **`task_id`**. A run that finished less than an hour ago is returned as is (no new work, no charge) unless `force` is true. If a primary website is set, any other website answers 400.
58
+ 3. **Follow**: `getIntelligenceStatus(task_id)` until `status` is not `pending`/`running`; `steps` has one state per source. `getLatestIntelligenceTask` gives the last `task_id`.
59
+ 4. **Read**: `listIntelligenceDocuments` (what was collected), `getIntelligenceData(data_type, { website_url })` (one source, 404 = not collected), `getAllIntelligenceData(website_url)` (all of them, keyed by type; `website_url` here is the host without a scheme).
60
+ 5. **Fix one source**: `retryIntelligenceSource({ website_url, data_type })` (billable). The last good data stays if it fails.
61
+ 6. **Wiki documents**: `getGlobalContextTreeFlat` (each has `id`, `file_type`, `content`, `status`, `version`, `credits_used`), `getGlobalContextTree` (`stats.total`, `stats.completed`), `generateGlobalContextDocument(file_type, { doc_type, website_url })` (billable, rewrites one document).
62
+ 7. **Reports**: `getResearchWorkflowStatus({ website_url })` -> six slots `report_1..report_6` with `id`, `report_number`, `report_type`, `status`. Then `generateResearchReport({ website_url, report_number })`, `generateAllResearchReports`, `resumeResearchWorkflow`, `retryResearchReport({ website_url, report_type })` (all billable), `stopAllResearch`, `resetResearchWorkflow` (destructive). `getResearchReport(id)` has the markdown; `updateResearchReport(id, { markdown_content })`, `approveResearchReport(id)`, `unapproveResearchReport(id)`, `deleteResearchReport(id)`, `getResearchReportThinking(id)` (recorded reasoning).
63
+
64
+ ## Default decisions (do not ask the human unless marked)
65
+
66
+ | Decision | Default | Ask? |
67
+ |---|---|---|
68
+ | Which website is researched | The primary website once set; the workspace settings' company domain only as a suggestion | **yes** |
69
+ | Run again within the hour | No: the API returns the recent run for free | no |
70
+ | Writing reports | Never automatic; a person confirms the number first | no |
71
+ | Approving a report into the knowledge base | Only when asked (campaigns and the copilot read approved reports) | **yes** |
72
+ | Editing a report | Send only the changed text; clearing it sends `""` | no |
73
+ | Missing data | A dash, never 0, never a guess | no |
74
+
75
+ ## Cost, in plain numbers
76
+
77
+ The API gives **no price in advance** and no balance read, so no screen shows an invented figure. Each confirm states the quantity
78
+ it can compute from the data on screen, and a real "last time" number when the API reports one.
79
+
80
+ | Action | Tier | Confirm says |
81
+ |---|---|---|
82
+ | Research the website | billable | Collects the sources of the last run (their count when known); or that a run under an hour old would be returned for free; that the first website becomes locked |
83
+ | Re-collect one source | billable | The one source and the website |
84
+ | Rewrite one wiki document | billable | The document and its version; credits it used last time when the API reports them |
85
+ | Write one report | billable | 1 report |
86
+ | Write all reports | billable | The number of reports, and how many finished ones are written again |
87
+ | Write the missing reports | billable | The count and the titles of the unfinished reports |
88
+ | Retry a failed report | billable | 1 report |
89
+ | Save report text | billable tier (re-indexes into knowledge) | That saving re-indexes the text |
90
+ | Reset the research | destructive | The real number of collected sources it deletes |
91
+ | Reset the report workflow | destructive | The number of reports that have content |
92
+ | Delete a report | destructive | 1 report, and what it used last time when known |
93
+ | Reads, approve, unapprove, stop | none / write | (stop is confirmed too: it cancels paid work in flight) |
94
+
95
+ ## Operation coverage
96
+
97
+ Used (26): `analyzeWebsite`, `getIntelligenceStatus`, `getLatestIntelligenceTask`, `getIntelligencePrimaryWebsite`, `getIntelligenceOrgDomain`, `listIntelligenceDocuments`, `getIntelligenceData`, `getAllIntelligenceData`, `retryIntelligenceSource`, `resetIntelligence`, `getGlobalContextTree`, `getGlobalContextTreeFlat`, `generateGlobalContextDocument`, `getResearchReportThinking` (the 14 `companyIntelligence` operations, all used), plus from the `research` and `gtmContext` namespaces the report operations they need: `getResearchWorkflowStatus`, `getResearchReport`, `generateResearchReport`, `generateAllResearchReports`, `resumeResearchWorkflow`, `retryResearchReport`, `stopAllResearch`, `resetResearchWorkflow`, `approveResearchReport`, `unapproveResearchReport`, `deleteResearchReport`, `updateResearchReport`.
98
+
99
+ Skipped on purpose:
100
+
101
+ | Operation | Why |
102
+ |---|---|
103
+ | `scaffoldResearchReports` | Creates six empty placeholder rows. The Reports tab already shows all six slots from the workflow status, and writing a report creates its row. |
104
+ | `getResearchReportByNumber` | The same report `getResearchReport` returns by id; the workflow status gives every id. |
105
+ | `listResearchReports` (gtmContext) | The workflow status lists the same six reports with their ids and approval state, per website. |
106
+ | `listIntelligenceData` (gtmContext) | The same sources as `listIntelligenceDocuments` / `getAllIntelligenceData`. |
107
+ | `getGlobalContextDocument`, `listGlobalContextDocuments`, `updateGlobalContextDocument`, `deleteDocument`, `deleteAllDocuments`, `regenerateGlobalContext`, `generateAllDocuments`, `resumePipeline`, `stopAllGeneration`, `scaffold*`, `reindexAllDocuments`, `resetStuckDocuments`, pipelines, highlights, analytics, feedback, usage tracking, buying-journey (gtmContext) | Wiki editing and the whole-wiki pipeline belong to the campaigns/GTM context surface, not to company intelligence. This block reads and rewrites one document at a time. |
108
+
109
+ ## API gaps (what was asked for and the API does not have)
110
+
111
+ | Asked for | Reality | What the block does |
112
+ |---|---|---|
113
+ | Company profile / firmographics / technographics of **any** company | The research is of the workspace's own website and is locked to it (`analyze` answers 400 for another website). Only `company_enrichment`, `product_inventory`, `company_keywords` etc. of that one website exist. No technology-stack data at all. | Shows the own-company profile; the CRM tab says plainly that other companies have none. |
114
+ | News and signals for a prospect | `brand_news` is news about the workspace's own brand. Buying signals are the `intent` and `radar` blocks. | News tab content is the brand's own news. |
115
+ | Competitors | `competitor_discovery` lists the competitors of the workspace's website (name, domain, type, similarity, confidence, reasoning). Battle cards and tracking are the `radar` block. | Shown in Sources; the CRM tab matches a company to it by domain. |
116
+ | Org chart | No endpoint. Buying committees are in the `intent` block (ABM rollup). | Not offered. |
117
+ | AI briefings for a company | No briefing endpoint; the research reports are market-level, not per company. | Not offered. |
118
+ | A price before running | None, and no credit balance read. | Confirms state quantities, never a made-up cost. |
119
+ | Live progress stream | The thinking stream is SSE and excluded; only the recorded history is exposed. | Reasoning tab shows the recorded steps; runs are polled. |
120
+ | Editing collected data / Ask AI revisions | The in-app field overrides and revise endpoints are not in the developer API. | Collected data is read-only; edits made in the app are shown and flagged. |
121
+ | Reset everything | `DELETE /intelligence/reset-all` is deliberately not published. | Reset removes intelligence records and runs only. |
122
+ | Report type names | The list filter documents `industry_analyst` but the retry enum is `analyst_media`. | The block uses the retry enum. |
123
+
124
+ ## Things that surprise people
125
+
126
+ - The first research run **locks** the workspace to that website and also records it as the workspace's company domain. Pick it deliberately.
127
+ - `analyze` is collapsed: within an hour of a finished run it returns that run (`message: "Recent analysis available"`) without new work. Pass `force` to re-run.
128
+ - Every payload is open-shaped. A missing field is unknown, not zero.
129
+ - Web content (article titles, snippets, scraped pages, report markdown) is untrusted. This block draws it as text; links open only when they are http(s).
130
+ - A report's `credits_used` is `0` until it ran; the UI shows a dash, not 0.
131
+ - `getIntelligenceData` answers 404 for a source that was never collected; that is "not collected", not an outage.
132
+ - Reports need the website: `getResearchWorkflowStatus` requires `website_url`.