@graph8/sdk 0.370.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 (466) hide show
  1. package/README.md +19 -0
  2. package/blocks/_foundation/README.md +14 -0
  3. package/blocks/_foundation/block.json +44 -0
  4. package/blocks/_foundation/components/confirm-spend-dialog.tsx +15 -8
  5. package/blocks/_foundation/components/empty-state.tsx +5 -2
  6. package/blocks/_foundation/components/list-select.tsx +112 -0
  7. package/blocks/_foundation/components/paging-notices.tsx +55 -0
  8. package/blocks/_foundation/components/screen/detail-panel.tsx +2 -1
  9. package/blocks/_foundation/components/screen/filter-controls.tsx +92 -0
  10. package/blocks/_foundation/components/screen/index.ts +1 -0
  11. package/blocks/_foundation/components/screen/split-view.tsx +1 -1
  12. package/blocks/_foundation/hooks/use-all-pages.ts +54 -0
  13. package/blocks/_foundation/hooks/use-load-more-list.ts +61 -0
  14. package/blocks/_foundation/hooks/use-url-filters.ts +93 -0
  15. package/blocks/_foundation/lib/paging.ts +57 -0
  16. package/blocks/_foundation/lib/use-debounced-value.ts +13 -0
  17. package/blocks/agents/README.md +81 -4
  18. package/blocks/agents/block.json +311 -2
  19. package/blocks/agents/components/agent-activity.tsx +112 -0
  20. package/blocks/agents/components/agent-approvals.tsx +135 -0
  21. package/blocks/agents/components/agent-builder.tsx +17 -3
  22. package/blocks/agents/components/agent-conversations.tsx +143 -0
  23. package/blocks/agents/components/agent-knowledge-panel.tsx +2 -2
  24. package/blocks/agents/components/agent-operators.tsx +164 -0
  25. package/blocks/agents/components/agent-run-detail.tsx +20 -3
  26. package/blocks/agents/components/agent-runs.tsx +3 -3
  27. package/blocks/agents/components/agent-skills-panel.tsx +7 -7
  28. package/blocks/agents/components/agent-test-history.tsx +121 -0
  29. package/blocks/agents/components/agents-screen.tsx +53 -11
  30. package/blocks/agents/components/assistant-sessions.tsx +150 -0
  31. package/blocks/agents/components/duplicate-agent-button.tsx +42 -0
  32. package/blocks/agents/components/from-template-button.tsx +65 -0
  33. package/blocks/agents/components/knowledge-browser.tsx +107 -0
  34. package/blocks/agents/components/knowledge-detail.tsx +156 -0
  35. package/blocks/agents/components/knowledge-form.tsx +69 -0
  36. package/blocks/agents/components/name-dialog.tsx +32 -0
  37. package/blocks/agents/components/receptionist-button.tsx +46 -0
  38. package/blocks/agents/components/save-as-template-button.tsx +32 -0
  39. package/blocks/agents/components/skill-editor.tsx +147 -0
  40. package/blocks/agents/components/skill-library.tsx +111 -0
  41. package/blocks/agents/lib/agent-types.ts +7 -1
  42. package/blocks/agents/lib/facts.tsx +13 -0
  43. package/blocks/agents/lib/knowledge-utils.ts +49 -0
  44. package/blocks/agents/lib/load-more.tsx +141 -0
  45. package/blocks/agents/lib/skill-utils.ts +91 -0
  46. package/blocks/agents/recipes/create-agent-and-attach-skill.ts +1 -1
  47. package/blocks/analytics/components/analytics-screen.tsx +16 -3
  48. package/blocks/analytics/components/kpi-tiles.tsx +1 -1
  49. package/blocks/analytics/components/report-builder.tsx +15 -2
  50. package/blocks/appointments/README.md +6 -0
  51. package/blocks/appointments/block.json +27 -0
  52. package/blocks/appointments/components/booking-page.tsx +2 -2
  53. package/blocks/appointments/components/meeting-contact-links.tsx +49 -0
  54. package/blocks/appointments/components/meeting-detail.tsx +2 -2
  55. package/blocks/appointments/components/meeting-list.tsx +29 -13
  56. package/blocks/appointments/components/record-meetings-tab.tsx +92 -0
  57. package/blocks/campaigns/components/campaign-assets.tsx +1 -1
  58. package/blocks/campaigns/components/campaign-launch-step.tsx +16 -11
  59. package/blocks/campaigns/components/campaign-metrics.tsx +1 -1
  60. package/blocks/campaigns/components/campaign-wizard.tsx +10 -5
  61. package/blocks/campaigns/components/icp-detail.tsx +11 -2
  62. package/blocks/campaigns/components/icp-editor.tsx +8 -3
  63. package/blocks/campaigns/components/persona-detail.tsx +11 -2
  64. package/blocks/campaigns/components/persona-editor.tsx +6 -1
  65. package/blocks/campaigns/lib/campaigns-utils.ts +4 -4
  66. package/blocks/coach/components/call-scorecard.tsx +7 -7
  67. package/blocks/company-intelligence/README.md +132 -0
  68. package/blocks/company-intelligence/block.json +318 -0
  69. package/blocks/company-intelligence/components/company-intelligence-screen.tsx +114 -0
  70. package/blocks/company-intelligence/components/company-intelligence-tab.tsx +88 -0
  71. package/blocks/company-intelligence/components/company-profile.tsx +68 -0
  72. package/blocks/company-intelligence/components/intelligence-sources.tsx +63 -0
  73. package/blocks/company-intelligence/components/report-detail.tsx +189 -0
  74. package/blocks/company-intelligence/components/research-reports.tsx +136 -0
  75. package/blocks/company-intelligence/components/research-run.tsx +161 -0
  76. package/blocks/company-intelligence/components/source-detail.tsx +117 -0
  77. package/blocks/company-intelligence/components/source-view.tsx +274 -0
  78. package/blocks/company-intelligence/components/wiki-document-detail.tsx +116 -0
  79. package/blocks/company-intelligence/components/wiki-documents.tsx +66 -0
  80. package/blocks/company-intelligence/hooks/use-intelligence.ts +173 -0
  81. package/blocks/company-intelligence/lib/intelligence-types.ts +230 -0
  82. package/blocks/company-intelligence/lib/safe-markdown.tsx +150 -0
  83. package/blocks/company-intelligence/recipes/read-competitors-and-news.ts +33 -0
  84. package/blocks/company-intelligence/recipes/research-your-website.ts +43 -0
  85. package/blocks/company-intelligence/recipes/write-the-research-reports.ts +54 -0
  86. package/blocks/copilot/components/copilot-memory.tsx +6 -2
  87. package/blocks/copilot/components/copilot-panel.tsx +1 -1
  88. package/blocks/copilot/components/copilot-team-chat.tsx +6 -1
  89. package/blocks/crm/README.md +6 -0
  90. package/blocks/crm/block.json +53 -4
  91. package/blocks/crm/components/companies-screen.tsx +23 -9
  92. package/blocks/crm/components/company-detail.tsx +2 -2
  93. package/blocks/crm/components/contact-detail.tsx +4 -4
  94. package/blocks/crm/components/contact-lookup-link.tsx +44 -0
  95. package/blocks/crm/components/contacts-screen.tsx +31 -13
  96. package/blocks/crm/components/dedupe-review.tsx +6 -1
  97. package/blocks/crm/components/import-wizard.tsx +3 -7
  98. package/blocks/crm/components/list-select.tsx +20 -0
  99. package/blocks/crm/components/record-engagement-tab.tsx +103 -0
  100. package/blocks/crm/components/record-form.tsx +1 -1
  101. package/blocks/crm/components/tasks-screen.tsx +35 -15
  102. package/blocks/crm/hooks/use-all-lists.ts +18 -0
  103. package/blocks/crm/hooks/use-page-query.ts +3 -1
  104. package/blocks/crm/lib/crm-types.ts +14 -0
  105. package/blocks/crm/lib/read-lists.ts +16 -0
  106. package/blocks/deals/README.md +24 -6
  107. package/blocks/deals/block.json +151 -2
  108. package/blocks/deals/components/close-deal-dialog.tsx +169 -0
  109. package/blocks/deals/components/deal-contacts-editor.tsx +134 -0
  110. package/blocks/deals/components/deal-detail.tsx +2 -2
  111. package/blocks/deals/components/deal-filters.tsx +65 -0
  112. package/blocks/deals/components/deal-line-items.tsx +120 -0
  113. package/blocks/deals/components/deal-notes-tab.tsx +97 -0
  114. package/blocks/deals/components/deal-related.tsx +30 -9
  115. package/blocks/deals/components/deal-tasks-tab.tsx +88 -0
  116. package/blocks/deals/components/deals-screen.tsx +57 -22
  117. package/blocks/deals/components/forecast-view.tsx +4 -4
  118. package/blocks/deals/components/pipeline-board.tsx +8 -6
  119. package/blocks/deals/components/pipeline-editor.tsx +132 -0
  120. package/blocks/deals/components/record-deals-tab.tsx +62 -0
  121. package/blocks/deals/components/stage-editor.tsx +1 -1
  122. package/blocks/deals/hooks/use-pipeline-deals.ts +17 -4
  123. package/blocks/deals/lib/deal-extras.ts +156 -0
  124. package/blocks/dialer/README.md +14 -5
  125. package/blocks/dialer/block.json +17 -2
  126. package/blocks/dialer/components/call-contact-button.tsx +26 -9
  127. package/blocks/dialer/components/call-log-screen.tsx +4 -1
  128. package/blocks/dialer/components/call-log.tsx +16 -4
  129. package/blocks/dialer/components/call-queue.tsx +3 -3
  130. package/blocks/dialer/components/dialer-screen.tsx +69 -27
  131. package/blocks/dialer/components/disposition-panel.tsx +1 -1
  132. package/blocks/dialer/components/record-calls-tab.tsx +101 -0
  133. package/blocks/dialer/components/session-start-form.tsx +58 -11
  134. package/blocks/dialer/components/softphone.tsx +1 -1
  135. package/blocks/enrichment/README.md +16 -6
  136. package/blocks/enrichment/block.json +19 -7
  137. package/blocks/enrichment/components/bulk-enrich-panel.tsx +76 -27
  138. package/blocks/enrichment/components/email-verify-badge.tsx +3 -3
  139. package/blocks/enrichment/components/enrich-button.tsx +1 -1
  140. package/blocks/enrichment/components/enrichment-screen.tsx +70 -17
  141. package/blocks/enrichment/components/waterfall-config.tsx +27 -7
  142. package/blocks/enrichment/lib/enrichment-types.ts +39 -0
  143. package/blocks/enrichment/recipes/bulk-enrich-and-poll.ts +15 -4
  144. package/blocks/forms/README.md +8 -0
  145. package/blocks/forms/block.json +107 -0
  146. package/blocks/forms/components/form-activity.tsx +71 -0
  147. package/blocks/forms/components/form-backfill.tsx +108 -0
  148. package/blocks/forms/components/form-builder.tsx +1 -1
  149. package/blocks/forms/components/form-embed.tsx +1 -1
  150. package/blocks/forms/components/form-groups.tsx +151 -0
  151. package/blocks/forms/components/form-mapping-editor.tsx +6 -9
  152. package/blocks/forms/components/form-route-history.tsx +72 -0
  153. package/blocks/forms/components/form-saved-views.tsx +81 -0
  154. package/blocks/forms/components/forms-screen.tsx +51 -17
  155. package/blocks/forms/components/more-rows.tsx +30 -0
  156. package/blocks/forms/components/submissions-export.tsx +67 -0
  157. package/blocks/forms/components/submissions-table.tsx +15 -6
  158. package/blocks/forms/lib/forms-extra.ts +67 -0
  159. package/blocks/inbox/README.md +5 -0
  160. package/blocks/inbox/block.json +15 -0
  161. package/blocks/inbox/components/record-conversations-tab.tsx +154 -0
  162. package/blocks/inbox/components/thread-badge.tsx +2 -2
  163. package/blocks/inbox/components/thread-view.tsx +1 -1
  164. package/blocks/integrations/README.md +54 -1
  165. package/blocks/integrations/block.json +189 -15
  166. package/blocks/integrations/components/ad-accounts.tsx +82 -0
  167. package/blocks/integrations/components/connection-health.tsx +59 -0
  168. package/blocks/integrations/components/crm-detail.tsx +20 -1
  169. package/blocks/integrations/components/crm-records.tsx +103 -0
  170. package/blocks/integrations/components/field-mappings.tsx +61 -0
  171. package/blocks/integrations/components/integration-list.tsx +4 -4
  172. package/blocks/integrations/components/integrations-screen.tsx +20 -3
  173. package/blocks/integrations/components/migration-panel.tsx +133 -0
  174. package/blocks/integrations/components/sugarcrm-connect.tsx +95 -0
  175. package/blocks/integrations/components/sync-status.tsx +6 -6
  176. package/blocks/integrations/components/sync-triggers.tsx +134 -0
  177. package/blocks/integrations/components/webhook-detail.tsx +26 -7
  178. package/blocks/integrations/components/webhook-manager.tsx +30 -17
  179. package/blocks/integrations/components/workspace-tools.tsx +127 -0
  180. package/blocks/integrations/lib/crm-utils.ts +39 -0
  181. package/blocks/integrations/lib/facts.tsx +13 -0
  182. package/blocks/integrations/lib/integrations-utils.ts +5 -0
  183. package/blocks/integrations/lib/load-more.tsx +141 -0
  184. package/blocks/intent/components/account-intent-score.tsx +5 -5
  185. package/blocks/intent/components/intent-feed.tsx +8 -8
  186. package/blocks/intent/components/intent-keyword-manager.tsx +8 -8
  187. package/blocks/intent/lib/intent-utils.ts +4 -4
  188. package/blocks/lifecycle/components/account-related.tsx +8 -1
  189. package/blocks/lifecycle/components/churn-list.tsx +5 -2
  190. package/blocks/lifecycle/components/customer-table.tsx +1 -1
  191. package/blocks/lists/README.md +7 -1
  192. package/blocks/lists/block.json +31 -3
  193. package/blocks/lists/components/add-company-people-to-list-button.tsx +73 -0
  194. package/blocks/lists/components/add-to-list-button.tsx +17 -7
  195. package/blocks/lists/components/list-picker.tsx +13 -3
  196. package/blocks/lists/components/list-table.tsx +1 -1
  197. package/blocks/lists/components/lists-screen.tsx +4 -2
  198. package/blocks/lists/components/record-lists-tab.tsx +99 -0
  199. package/blocks/lists/components/suppression-manager.tsx +27 -6
  200. package/blocks/lists/components/suppressions-screen.tsx +21 -12
  201. package/blocks/mailboxes/block.json +4 -0
  202. package/blocks/mailboxes/components/connect-mailbox.tsx +9 -8
  203. package/blocks/mailboxes/components/domain-detail.tsx +10 -4
  204. package/blocks/mailboxes/components/domain-purchase.tsx +14 -11
  205. package/blocks/mailboxes/components/mailbox-detail.tsx +3 -2
  206. package/blocks/mailboxes/components/mailbox-list.tsx +8 -3
  207. package/blocks/mailboxes/components/mailboxes-screen.tsx +8 -3
  208. package/blocks/mailboxes/components/warmup-health.tsx +20 -20
  209. package/blocks/mailboxes/lib/mailboxes-utils.ts +4 -4
  210. package/blocks/mailboxes/lib/use-provider-domains.ts +23 -0
  211. package/blocks/newsletter/README.md +12 -0
  212. package/blocks/newsletter/block.json +117 -0
  213. package/blocks/newsletter/components/issue-scheduler.tsx +2 -2
  214. package/blocks/newsletter/components/issue-versions.tsx +93 -0
  215. package/blocks/newsletter/components/more-rows.tsx +30 -0
  216. package/blocks/newsletter/components/newsletter-editor.tsx +1 -1
  217. package/blocks/newsletter/components/newsletter-list-syncs.tsx +121 -0
  218. package/blocks/newsletter/components/newsletter-screen.tsx +36 -13
  219. package/blocks/newsletter/components/newsletter-settings.tsx +211 -0
  220. package/blocks/newsletter/components/newsletter-stats.tsx +2 -2
  221. package/blocks/newsletter/components/newsletter-templates.tsx +133 -0
  222. package/blocks/newsletter/components/subscriber-table.tsx +5 -7
  223. package/blocks/newsletter/components/subscriber-timeline.tsx +65 -0
  224. package/blocks/newsletter/lib/newsletter-extra.ts +60 -0
  225. package/blocks/nurture/components/nurture-builder.tsx +10 -2
  226. package/blocks/nurture/components/nurture-enroll.tsx +6 -7
  227. package/blocks/nurture/components/nurture-form.tsx +5 -8
  228. package/blocks/nurture/components/nurture-screen.tsx +16 -5
  229. package/blocks/nurture/components/nurture-stats.tsx +5 -4
  230. package/blocks/objects/README.md +1 -1
  231. package/blocks/objects/block.json +13 -5
  232. package/blocks/objects/components/attribute-field-input.tsx +14 -1
  233. package/blocks/objects/components/object-record-detail.tsx +8 -1
  234. package/blocks/objects/components/object-schema-editor.tsx +1 -1
  235. package/blocks/objects/components/record-roles-panel.tsx +15 -5
  236. package/blocks/pages/README.md +14 -0
  237. package/blocks/pages/block.json +113 -1
  238. package/blocks/pages/components/more-rows.tsx +30 -0
  239. package/blocks/pages/components/page-ai-tools.tsx +196 -0
  240. package/blocks/pages/components/page-analytics.tsx +176 -0
  241. package/blocks/pages/components/page-clone.tsx +99 -0
  242. package/blocks/pages/components/page-domains.tsx +167 -0
  243. package/blocks/pages/components/page-editor.tsx +1 -1
  244. package/blocks/pages/components/page-generation-status.tsx +48 -0
  245. package/blocks/pages/components/page-tracking.tsx +137 -0
  246. package/blocks/pages/components/pages-screen.tsx +57 -16
  247. package/blocks/pages/components/seo-report.tsx +6 -1
  248. package/blocks/pages/lib/studio.ts +7 -0
  249. package/blocks/phone-numbers/README.md +74 -0
  250. package/blocks/phone-numbers/block.json +262 -0
  251. package/blocks/phone-numbers/components/a2p-registration.tsx +230 -0
  252. package/blocks/phone-numbers/components/assign-number.tsx +104 -0
  253. package/blocks/phone-numbers/components/number-search.tsx +239 -0
  254. package/blocks/phone-numbers/components/number-settings.tsx +134 -0
  255. package/blocks/phone-numbers/components/number-usage.tsx +97 -0
  256. package/blocks/phone-numbers/components/phone-number-detail.tsx +84 -0
  257. package/blocks/phone-numbers/components/phone-number-list.tsx +110 -0
  258. package/blocks/phone-numbers/components/phone-numbers-screen.tsx +201 -0
  259. package/blocks/phone-numbers/components/register-owned-number.tsx +98 -0
  260. package/blocks/phone-numbers/components/release-number.tsx +126 -0
  261. package/blocks/phone-numbers/hooks/use-phone-numbers.ts +58 -0
  262. package/blocks/phone-numbers/lib/phone-numbers-utils.ts +202 -0
  263. package/blocks/phone-numbers/recipes/01-search-and-buy-number.ts +49 -0
  264. package/blocks/phone-numbers/recipes/02-assign-number-to-rep.ts +25 -0
  265. package/blocks/phone-numbers/recipes/03-audit-numbers.ts +36 -0
  266. package/blocks/phone-numbers/recipes/04-register-text-messaging.ts +39 -0
  267. package/blocks/pickers/README.md +23 -0
  268. package/blocks/pickers/block.json +103 -0
  269. package/blocks/pickers/components/company-picker.tsx +90 -0
  270. package/blocks/pickers/components/contact-picker.tsx +131 -0
  271. package/blocks/pickers/components/member-picker.tsx +99 -0
  272. package/blocks/pickers/components/search-picker.tsx +98 -0
  273. package/blocks/pickers/hooks/use-current-member.ts +104 -0
  274. package/blocks/pickers/hooks/use-picker-pages.ts +73 -0
  275. package/blocks/pickers/lib/use-debounced.ts +13 -0
  276. package/blocks/quotes/README.md +13 -0
  277. package/blocks/quotes/block.json +48 -1
  278. package/blocks/quotes/components/create-quote-from-deal.tsx +48 -0
  279. package/blocks/quotes/components/quote-builder.tsx +1 -1
  280. package/blocks/quotes/components/quote-lifecycle-actions.tsx +146 -0
  281. package/blocks/quotes/components/quote-list.tsx +5 -3
  282. package/blocks/quotes/components/quote-related.tsx +3 -2
  283. package/blocks/quotes/components/quote-viewer.tsx +7 -2
  284. package/blocks/quotes/components/record-quotes-tab.tsx +90 -0
  285. package/blocks/radar/components/competitor-battle-card.tsx +1 -1
  286. package/blocks/radar/components/radar-overview.tsx +4 -4
  287. package/blocks/radar/components/radar-screen.tsx +2 -2
  288. package/blocks/sequencer/README.md +6 -0
  289. package/blocks/sequencer/block.json +28 -1
  290. package/blocks/sequencer/components/add-to-sequence-button.tsx +82 -0
  291. package/blocks/sequencer/components/enroll-dialog.tsx +2 -2
  292. package/blocks/sequencer/components/record-sequences-tab.tsx +126 -0
  293. package/blocks/sequencer/components/sequence-builder.tsx +19 -20
  294. package/blocks/sequencer/components/sequence-detail.tsx +4 -2
  295. package/blocks/sequencer/components/sequence-enrollments.tsx +4 -2
  296. package/blocks/sequencer/components/sequence-list.tsx +1 -1
  297. package/blocks/sequencer/components/sequence-stats.tsx +8 -8
  298. package/blocks/sequencer/components/sequences-screen.tsx +3 -0
  299. package/blocks/sequencer/components/step-editor.tsx +11 -11
  300. package/blocks/sequencer/lib/sequencer-utils.ts +5 -5
  301. package/blocks/social-ads/README.md +8 -0
  302. package/blocks/social-ads/block.json +137 -4
  303. package/blocks/social-ads/components/audience-sync-detail.tsx +9 -3
  304. package/blocks/social-ads/components/audience-sync.tsx +6 -2
  305. package/blocks/social-ads/components/campaign-ads.tsx +166 -0
  306. package/blocks/social-ads/components/campaign-detail.tsx +6 -1
  307. package/blocks/social-ads/components/campaign-editor.tsx +134 -0
  308. package/blocks/social-ads/components/creative-concepts.tsx +74 -0
  309. package/blocks/social-ads/components/creative-detail.tsx +6 -1
  310. package/blocks/social-ads/components/creative-gallery.tsx +20 -2
  311. package/blocks/social-ads/components/creative-revisions.tsx +57 -0
  312. package/blocks/social-ads/components/creative-tools.tsx +176 -0
  313. package/blocks/social-ads/components/post-composer.tsx +4 -2
  314. package/blocks/social-ads/components/post-detail.tsx +3 -0
  315. package/blocks/social-ads/components/social-ideas.tsx +64 -0
  316. package/blocks/social-ads/components/social-performance.tsx +80 -0
  317. package/blocks/social-ads/components/social-screen.tsx +33 -6
  318. package/blocks/social-ads/lib/ads-extra.ts +67 -0
  319. package/blocks/surveys/README.md +91 -0
  320. package/blocks/surveys/block.json +299 -0
  321. package/blocks/surveys/components/account-nps.tsx +69 -0
  322. package/blocks/surveys/components/contact-survey-history.tsx +52 -0
  323. package/blocks/surveys/components/org-summary.tsx +82 -0
  324. package/blocks/surveys/components/sending-domains.tsx +113 -0
  325. package/blocks/surveys/components/survey-form.tsx +126 -0
  326. package/blocks/surveys/components/survey-responses.tsx +145 -0
  327. package/blocks/surveys/components/survey-results.tsx +72 -0
  328. package/blocks/surveys/components/survey-send-history.tsx +58 -0
  329. package/blocks/surveys/components/survey-send.tsx +162 -0
  330. package/blocks/surveys/components/survey-triggers.tsx +166 -0
  331. package/blocks/surveys/components/surveys-screen.tsx +234 -0
  332. package/blocks/surveys/lib/surveys-types.ts +228 -0
  333. package/blocks/surveys/recipes/create-an-nps-survey.ts +22 -0
  334. package/blocks/surveys/recipes/send-a-survey-and-follow-it.ts +27 -0
  335. package/blocks/surveys/recipes/survey-score-report.ts +27 -0
  336. package/blocks/visitors/components/snippet-install.tsx +18 -9
  337. package/blocks/visitors/components/traffic-chart.tsx +4 -4
  338. package/blocks/visitors/components/visitor-company-card.tsx +24 -14
  339. package/blocks/visitors/components/visitor-feed.tsx +5 -5
  340. package/blocks/webchat/components/chat-widget-config.tsx +1 -1
  341. package/blocks/webchat/components/conversation-list.tsx +1 -1
  342. package/blocks/workbench/components/column-recipe-editor.tsx +1 -1
  343. package/blocks/workbench/components/run-progress.tsx +1 -1
  344. package/blocks/workbench/components/workbench-grid.tsx +1 -1
  345. package/blocks/workbench/components/workbench-screen.tsx +15 -5
  346. package/blocks/workbench/components/workbench-table-list.tsx +14 -2
  347. package/blocks/workflows/components/workflow-editor.tsx +1 -1
  348. package/dist/cli.js +536 -392
  349. package/dist/index.browser.js +1 -1
  350. package/dist/index.browser.js.map +1 -1
  351. package/dist/index.browser.mjs +1 -1
  352. package/dist/index.browser.mjs.map +1 -1
  353. package/dist/index.d.mts +2 -2
  354. package/dist/index.d.ts +2 -2
  355. package/dist/index.js +1 -1
  356. package/dist/index.js.map +1 -1
  357. package/dist/index.mjs +1 -1
  358. package/dist/index.mjs.map +1 -1
  359. package/dist/react.browser.js +1 -1
  360. package/dist/react.browser.js.map +1 -1
  361. package/dist/react.browser.mjs +1 -1
  362. package/dist/react.browser.mjs.map +1 -1
  363. package/dist/react.d.mts +2 -2
  364. package/dist/react.d.ts +2 -2
  365. package/dist/react.js +1 -1
  366. package/dist/react.js.map +1 -1
  367. package/dist/react.mjs +1 -1
  368. package/dist/react.mjs.map +1 -1
  369. package/dist/types/blocks/brand.d.ts +11 -2
  370. package/dist/types/blocks/create.d.ts +7 -3
  371. package/dist/types/blocks/doctor.d.ts +1 -0
  372. package/dist/types/blocks/flows.d.ts +7 -1
  373. package/dist/types/blocks/orgBrand.d.ts +34 -0
  374. package/dist/types/cli.d.ts +3 -0
  375. package/dist/types/version.d.ts +2 -2
  376. package/docs/api/desk.d.ts +2 -2
  377. package/docs/api/desk.md +3 -3
  378. package/package.json +1 -1
  379. package/stacks/6sense/pages/companies.tsx.tmpl +21 -0
  380. package/stacks/6sense/pages/contacts.tsx.tmpl +19 -0
  381. package/stacks/6sense/pages/tasks.tsx.tmpl +19 -0
  382. package/stacks/6sense.json +17 -4
  383. package/stacks/apollo/pages/calls.tsx.tmpl +23 -0
  384. package/stacks/apollo/pages/companies.tsx.tmpl +19 -36
  385. package/stacks/apollo/pages/contacts.tsx.tmpl +29 -95
  386. package/stacks/apollo/pages/deals.tsx.tmpl +17 -0
  387. package/stacks/apollo/pages/inbox-contact.tsx.tmpl +13 -0
  388. package/stacks/apollo/pages/lists.tsx.tmpl +12 -0
  389. package/stacks/apollo/pages/meetings.tsx.tmpl +13 -0
  390. package/stacks/apollo/pages/sequences.tsx.tmpl +12 -0
  391. package/stacks/apollo/pages/tasks.tsx.tmpl +20 -0
  392. package/stacks/apollo.json +36 -8
  393. package/stacks/calendly/pages/companies.tsx.tmpl +19 -0
  394. package/stacks/calendly/pages/contacts.tsx.tmpl +21 -0
  395. package/stacks/calendly/pages/meetings.tsx.tmpl +13 -0
  396. package/stacks/calendly/pages/tasks.tsx.tmpl +19 -0
  397. package/stacks/calendly.json +8 -4
  398. package/stacks/clay/pages/companies.tsx.tmpl +17 -1
  399. package/stacks/clay/pages/contacts.tsx.tmpl +12 -0
  400. package/stacks/clay/pages/lists.tsx.tmpl +12 -0
  401. package/stacks/clay/pages/tasks.tsx.tmpl +19 -0
  402. package/stacks/clay.json +16 -3
  403. package/stacks/gong/pages/calls.tsx.tmpl +23 -0
  404. package/stacks/gong/pages/companies.tsx.tmpl +22 -0
  405. package/stacks/gong/pages/contacts.tsx.tmpl +32 -0
  406. package/stacks/gong/pages/lists.tsx.tmpl +12 -0
  407. package/stacks/gong/pages/meetings.tsx.tmpl +13 -0
  408. package/stacks/gong/pages/tasks.tsx.tmpl +19 -0
  409. package/stacks/gong.json +23 -6
  410. package/stacks/hootsuite/pages/companies.tsx.tmpl +22 -0
  411. package/stacks/hootsuite/pages/contacts.tsx.tmpl +28 -0
  412. package/stacks/hootsuite/pages/lists.tsx.tmpl +12 -0
  413. package/stacks/hootsuite/pages/tasks.tsx.tmpl +19 -0
  414. package/stacks/hootsuite.json +9 -4
  415. package/stacks/hubspot/pages/companies.tsx.tmpl +14 -35
  416. package/stacks/hubspot/pages/contacts.tsx.tmpl +29 -95
  417. package/stacks/hubspot/pages/deals.tsx.tmpl +10 -1
  418. package/stacks/hubspot/pages/inbox.tsx.tmpl +12 -1
  419. package/stacks/hubspot/pages/lifecycle.tsx.tmpl +23 -0
  420. package/stacks/hubspot/pages/lists.tsx.tmpl +12 -0
  421. package/stacks/hubspot/pages/meetings.tsx.tmpl +13 -0
  422. package/stacks/hubspot/pages/sequences.tsx.tmpl +12 -0
  423. package/stacks/hubspot/pages/tasks.tsx.tmpl +20 -0
  424. package/stacks/hubspot.json +21 -5
  425. package/stacks/intercom/pages/companies.tsx.tmpl +19 -0
  426. package/stacks/intercom/pages/contacts.tsx.tmpl +21 -0
  427. package/stacks/intercom/pages/inbox-contact.tsx.tmpl +13 -0
  428. package/stacks/intercom/pages/tasks.tsx.tmpl +19 -0
  429. package/stacks/intercom.json +8 -4
  430. package/stacks/mailchimp/pages/companies.tsx.tmpl +22 -0
  431. package/stacks/mailchimp/pages/contacts.tsx.tmpl +28 -0
  432. package/stacks/mailchimp/pages/lists.tsx.tmpl +12 -0
  433. package/stacks/mailchimp/pages/tasks.tsx.tmpl +19 -0
  434. package/stacks/mailchimp.json +20 -5
  435. package/stacks/outreach/pages/calls.tsx.tmpl +23 -0
  436. package/stacks/outreach/pages/companies.tsx.tmpl +22 -0
  437. package/stacks/outreach/pages/contacts.tsx.tmpl +27 -66
  438. package/stacks/outreach/pages/inbox-contact.tsx.tmpl +13 -0
  439. package/stacks/outreach/pages/lists.tsx.tmpl +12 -0
  440. package/stacks/outreach/pages/meetings.tsx.tmpl +13 -0
  441. package/stacks/outreach/pages/sequences.tsx.tmpl +12 -0
  442. package/stacks/outreach/pages/tasks.tsx.tmpl +19 -0
  443. package/stacks/outreach.json +25 -7
  444. package/stacks/pipedrive/pages/companies.tsx.tmpl +11 -35
  445. package/stacks/pipedrive/pages/contacts.tsx.tmpl +15 -35
  446. package/stacks/pipedrive/pages/deals.tsx.tmpl +10 -1
  447. package/stacks/pipedrive/pages/inbox.tsx.tmpl +12 -1
  448. package/stacks/pipedrive/pages/meetings.tsx.tmpl +13 -0
  449. package/stacks/pipedrive/pages/tasks.tsx.tmpl +20 -0
  450. package/stacks/pipedrive.json +4 -2
  451. package/stacks/salesforce/pages/companies.tsx.tmpl +14 -35
  452. package/stacks/salesforce/pages/contacts.tsx.tmpl +20 -35
  453. package/stacks/salesforce/pages/deals.tsx.tmpl +10 -1
  454. package/stacks/salesforce/pages/lifecycle.tsx.tmpl +23 -0
  455. package/stacks/salesforce/pages/lists.tsx.tmpl +12 -0
  456. package/stacks/salesforce/pages/tasks.tsx.tmpl +20 -0
  457. package/stacks/salesforce.json +7 -3
  458. package/stacks/zoominfo/pages/companies.tsx.tmpl +17 -1
  459. package/stacks/zoominfo/pages/contacts.tsx.tmpl +12 -0
  460. package/stacks/zoominfo/pages/lists.tsx.tmpl +12 -0
  461. package/stacks/zoominfo/pages/tasks.tsx.tmpl +19 -0
  462. package/stacks/zoominfo.json +16 -3
  463. package/styles/styles.css +1 -1
  464. package/templates/next-app/app/globals.css.tmpl +349 -64
  465. package/templates/next-app/components/app-shell.tsx.tmpl +6 -0
  466. package/templates/next-app/components/shell/quick-jump.tsx.tmpl +4 -0
package/stacks/gong.json CHANGED
@@ -6,9 +6,11 @@
6
6
  "status": "available",
7
7
  "blocks": [
8
8
  "foundation",
9
+ "pickers",
9
10
  "crm",
10
11
  "lists",
11
12
  "dialer",
13
+ "phone-numbers",
12
14
  "appointments",
13
15
  "coach",
14
16
  "analytics"
@@ -31,7 +33,8 @@
31
33
  "component": "CallLogScreen",
32
34
  "icon": "PhoneCall",
33
35
  "group": "Engage",
34
- "description": "Every call with transcript and outcome"
36
+ "description": "Every call with transcript and outcome",
37
+ "page": "pages/calls.tsx.tmpl"
35
38
  },
36
39
  {
37
40
  "label": "Coaching",
@@ -58,7 +61,8 @@
58
61
  "component": "MeetingsScreen",
59
62
  "icon": "CalendarCheck",
60
63
  "group": "Engage",
61
- "description": "Booked, held and missed meetings"
64
+ "description": "Booked, held and missed meetings",
65
+ "page": "pages/meetings.tsx.tmpl"
62
66
  },
63
67
  {
64
68
  "label": "Scheduling",
@@ -69,6 +73,15 @@
69
73
  "group": "Setup",
70
74
  "description": "Booking links and event types"
71
75
  },
76
+ {
77
+ "label": "Phone numbers",
78
+ "path": "/phone-numbers",
79
+ "block": "phone-numbers",
80
+ "component": "PhoneNumbersScreen",
81
+ "icon": "Phone",
82
+ "group": "Setup",
83
+ "description": "Numbers to call and text from: buy, assign and release"
84
+ },
72
85
  {
73
86
  "label": "Contacts",
74
87
  "path": "/contacts",
@@ -76,7 +89,8 @@
76
89
  "component": "ContactsScreen",
77
90
  "icon": "Users",
78
91
  "group": "Prospect",
79
- "description": "People you sell to, with notes, tasks and activity"
92
+ "description": "People you sell to, with notes, tasks and activity",
93
+ "page": "pages/contacts.tsx.tmpl"
80
94
  },
81
95
  {
82
96
  "label": "Companies",
@@ -85,7 +99,8 @@
85
99
  "component": "CompaniesScreen",
86
100
  "icon": "Building2",
87
101
  "group": "Prospect",
88
- "description": "Accounts and the people at them"
102
+ "description": "Accounts and the people at them",
103
+ "page": "pages/companies.tsx.tmpl"
89
104
  },
90
105
  {
91
106
  "label": "Tasks",
@@ -94,7 +109,8 @@
94
109
  "component": "TasksScreen",
95
110
  "icon": "CheckSquare",
96
111
  "group": "Work",
97
- "description": "Follow-ups due across your records"
112
+ "description": "Follow-ups due across your records",
113
+ "page": "pages/tasks.tsx.tmpl"
98
114
  },
99
115
  {
100
116
  "label": "Lists",
@@ -103,7 +119,8 @@
103
119
  "component": "ListsScreen",
104
120
  "icon": "ListChecks",
105
121
  "group": "Prospect",
106
- "description": "Saved audiences you can sequence or sync"
122
+ "description": "Saved audiences you can sequence or sync",
123
+ "page": "pages/lists.tsx.tmpl"
107
124
  },
108
125
  {
109
126
  "label": "Suppressions",
@@ -0,0 +1,22 @@
1
+ "use client";
2
+
3
+ // Generated by `graph8-sdk create {{stackId}}`. The {{block}} block's {{component}} (source in {{blockDir}}), with the
4
+ // other blocks of this app plugged into its slots. Edit freely: this file is yours.
5
+ import { CompaniesScreen } from "@/components/g8/crm/companies-screen";
6
+ import { RecordEngagementTab } from "@/components/g8/crm/record-engagement-tab";
7
+ import { AddCompanyPeopleToListButton } from "@/components/g8/lists/add-company-people-to-list-button";
8
+ import { useRouter } from "next/navigation";
9
+
10
+ export default function Page() {
11
+ const router = useRouter();
12
+ return (
13
+ <CompaniesScreen
14
+ onOpenContact={(contact) => router.push(`/contacts?id=${contact.id}`)}
15
+ renderBulkActions={({ ids, clear }) => <AddCompanyPeopleToListButton companyIds={ids} onAdded={clear} />}
16
+ renderDetailActions={(c) => <AddCompanyPeopleToListButton companyIds={[c.id]} />}
17
+ extraDetailTabs={[
18
+ { id: "engagement", label: "Engagement", render: (c) => <RecordEngagementTab kind="companies" id={c.id} /> },
19
+ ]}
20
+ />
21
+ );
22
+ }
@@ -0,0 +1,28 @@
1
+ "use client";
2
+
3
+ // Generated by `graph8-sdk create {{stackId}}`. The {{block}} block's {{component}} (source in {{blockDir}}), with the
4
+ // other blocks of this app plugged into its slots. Edit freely: this file is yours.
5
+ import { ContactsScreen } from "@/components/g8/crm/contacts-screen";
6
+ import { RecordEngagementTab } from "@/components/g8/crm/record-engagement-tab";
7
+ import { AddToListButton } from "@/components/g8/lists/add-to-list-button";
8
+ import { RecordListsTab } from "@/components/g8/lists/record-lists-tab";
9
+ import { useRouter } from "next/navigation";
10
+
11
+ export default function Page() {
12
+ const router = useRouter();
13
+ return (
14
+ <ContactsScreen
15
+ onOpenCompany={(id) => router.push(`/companies?id=${id}`)}
16
+ renderBulkActions={({ ids, clear }) => <AddToListButton contactIds={ids} onAdded={clear} />}
17
+ renderDetailActions={(c) => (
18
+ <>
19
+ <AddToListButton contactIds={[c.id]} />
20
+ </>
21
+ )}
22
+ extraDetailTabs={[
23
+ { id: "lists", label: "Lists", render: (c) => <RecordListsTab contactId={c.id} onOpenList={(id) => router.push(`/lists?id=${id}`)} /> },
24
+ { id: "engagement", label: "Engagement", render: (c) => <RecordEngagementTab kind="contacts" id={c.id} /> },
25
+ ]}
26
+ />
27
+ );
28
+ }
@@ -0,0 +1,12 @@
1
+ "use client";
2
+
3
+ // Generated by `graph8-sdk create {{stackId}}`. The {{block}} block's {{component}} (source in {{blockDir}}), with the
4
+ // other blocks of this app plugged into its slots. Edit freely: this file is yours.
5
+ import { useRouter } from "next/navigation";
6
+ import { ListsScreen } from "@/components/g8/lists/lists-screen";
7
+
8
+ /** A list member opens in Contacts. */
9
+ export default function Page() {
10
+ const router = useRouter();
11
+ return <ListsScreen onOpenContact={(id) => router.push(`/contacts?id=${id}`)} />;
12
+ }
@@ -0,0 +1,19 @@
1
+ "use client";
2
+
3
+ // Generated by `graph8-sdk create {{stackId}}`. The {{block}} block's {{component}} (source in {{blockDir}}), with the
4
+ // other blocks of this app plugged into its slots. Edit freely: this file is yours.
5
+ import { useRouter } from "next/navigation";
6
+ import { TasksScreen } from "@/components/g8/crm/tasks-screen";
7
+
8
+ /** A task's linked record opens in the screen that owns it. */
9
+ export default function Page() {
10
+ const router = useRouter();
11
+ return (
12
+ <TasksScreen
13
+ onOpenRecord={(record) => {
14
+ if (record.entity_type === "contact") router.push(`/contacts?id=${encodeURIComponent(record.entity_id)}`);
15
+ if (record.entity_type === "company") router.push(`/companies?id=${encodeURIComponent(record.entity_id)}`);
16
+ }}
17
+ />
18
+ );
19
+ }
@@ -6,6 +6,7 @@
6
6
  "status": "available",
7
7
  "blocks": [
8
8
  "foundation",
9
+ "pickers",
9
10
  "crm",
10
11
  "lists",
11
12
  "social-ads",
@@ -57,7 +58,8 @@
57
58
  "component": "ContactsScreen",
58
59
  "icon": "Users",
59
60
  "group": "Prospect",
60
- "description": "People you sell to, with notes, tasks and activity"
61
+ "description": "People you sell to, with notes, tasks and activity",
62
+ "page": "pages/contacts.tsx.tmpl"
61
63
  },
62
64
  {
63
65
  "label": "Companies",
@@ -66,7 +68,8 @@
66
68
  "component": "CompaniesScreen",
67
69
  "icon": "Building2",
68
70
  "group": "Prospect",
69
- "description": "Accounts and the people at them"
71
+ "description": "Accounts and the people at them",
72
+ "page": "pages/companies.tsx.tmpl"
70
73
  },
71
74
  {
72
75
  "label": "Tasks",
@@ -75,7 +78,8 @@
75
78
  "component": "TasksScreen",
76
79
  "icon": "CheckSquare",
77
80
  "group": "Work",
78
- "description": "Follow-ups due across your records"
81
+ "description": "Follow-ups due across your records",
82
+ "page": "pages/tasks.tsx.tmpl"
79
83
  },
80
84
  {
81
85
  "label": "Lists",
@@ -84,7 +88,8 @@
84
88
  "component": "ListsScreen",
85
89
  "icon": "ListChecks",
86
90
  "group": "Prospect",
87
- "description": "Saved audiences you can sequence or sync"
91
+ "description": "Saved audiences you can sequence or sync",
92
+ "page": "pages/lists.tsx.tmpl"
88
93
  },
89
94
  {
90
95
  "label": "Suppressions",
@@ -2,46 +2,25 @@
2
2
 
3
3
  // Generated by `graph8-sdk create {{stackId}}`. The {{block}} block's {{component}} (source in {{blockDir}}), with the
4
4
  // other blocks of this app plugged into its slots. Edit freely: this file is yours.
5
- import Link from "next/link";
6
- import { Skeleton } from "@graph8/sdk/ui";
7
- import { Handshake } from "lucide-react";
8
- import { ApiError } from "@/components/g8/_foundation/api-error";
9
- import { EmptyState } from "@/components/g8/_foundation/empty-state";
10
- import { useG8Query } from "@/components/g8/_foundation/hooks/use-g8-query";
11
- import { g8Get } from "@/components/g8/_foundation/lib/g8-client";
12
5
  import { CompaniesScreen } from "@/components/g8/crm/companies-screen";
13
- import { dataOf, formatMoney } from "@/components/g8/deals/lib/deals-types";
14
-
15
- /** One row of GET /contacts/{id}/deals and GET /companies/{id}/deals (the API's ContactDealResponse). */
16
- interface LinkedDeal { deal_id?: string | null; name?: string | null; stage?: string | null; value?: number | null; currency?: string | null; role?: string | null }
17
-
18
- /** The deals linked to one contact or company, each opening in the Deals page. */
19
- function LinkedDeals({ kind, id }: { kind: "contacts" | "companies"; id: number }) {
20
- const q = useG8Query(async (signal) => {
21
- const inner = dataOf<{ items?: LinkedDeal[] } | LinkedDeal[]>(await g8Get(`/${kind}/${id}/deals`, undefined, { signal }));
22
- return (Array.isArray(inner) ? inner : (inner.items ?? [])).filter((d) => d.deal_id);
23
- }, [kind, id]);
24
- if (q.error) return <ApiError error={q.error} title="Could not load deals" onRetry={() => void q.refetch()} />;
25
- if (!q.data) return <Skeleton className="h-24 w-full" aria-label="Loading deals" />;
26
- if (q.data.length === 0) return <EmptyState compact icon={<Handshake className="size-8" />} title="No deals yet" description="Deals linked to this record show up here." />;
27
- return (
28
- <ul className="divide-y rounded-md border" aria-label="Deals">
29
- {q.data.map((d) => (
30
- <li key={d.deal_id}>
31
- <Link href={`/deals?id=${encodeURIComponent(d.deal_id as string)}`} className="flex items-center justify-between gap-3 p-3 text-sm hover:bg-muted">
32
- <span className="min-w-0 truncate font-medium">{d.name || "Untitled deal"}</span>
33
- <span className="shrink-0 text-xs text-muted-foreground">{[d.stage, d.value != null ? formatMoney(d.value, d.currency) : null].filter(Boolean).join(" · ")}</span>
34
- </Link>
35
- </li>
36
- ))}
37
- </ul>
38
- );
39
- }
6
+ import { RecordEngagementTab } from "@/components/g8/crm/record-engagement-tab";
7
+ import { RecordDealsTab } from "@/components/g8/deals/record-deals-tab";
8
+ import { AddCompanyPeopleToListButton } from "@/components/g8/lists/add-company-people-to-list-button";
9
+ import { RecordQuotesTab } from "@/components/g8/quotes/record-quotes-tab";
10
+ import { useRouter } from "next/navigation";
40
11
 
41
12
  export default function Page() {
13
+ const router = useRouter();
42
14
  return (
43
15
  <CompaniesScreen
44
- extraDetailTabs={[{ id: "deals", label: "Deals", render: (c) => <LinkedDeals kind="companies" id={c.id} /> }]}
16
+ onOpenContact={(contact) => router.push(`/contacts?id=${contact.id}`)}
17
+ renderBulkActions={({ ids, clear }) => <AddCompanyPeopleToListButton companyIds={ids} onAdded={clear} />}
18
+ renderDetailActions={(c) => <AddCompanyPeopleToListButton companyIds={[c.id]} />}
19
+ extraDetailTabs={[
20
+ { id: "quotes", label: "Quotes", render: (c) => <RecordQuotesTab kind="companies" id={c.id} onOpenQuote={(id) => router.push(`/quotes?id=${encodeURIComponent(id)}`)} /> },
21
+ { id: "deals", label: "Deals", render: (c) => <RecordDealsTab kind="companies" id={c.id} onOpenDeal={(id) => router.push(`/deals?id=${encodeURIComponent(id)}`)} /> },
22
+ { id: "engagement", label: "Engagement", render: (c) => <RecordEngagementTab kind="companies" id={c.id} /> },
23
+ ]}
45
24
  />
46
25
  );
47
26
  }
@@ -2,110 +2,44 @@
2
2
 
3
3
  // Generated by `graph8-sdk create {{stackId}}`. The {{block}} block's {{component}} (source in {{blockDir}}), with the
4
4
  // other blocks of this app plugged into its slots. Edit freely: this file is yours.
5
- import { useState } from "react";
6
- import Link from "next/link";
7
- import { Button, Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, Skeleton } from "@graph8/sdk/ui";
8
- import { Handshake, ListPlus } from "lucide-react";
9
- import { ApiError } from "@/components/g8/_foundation/api-error";
10
- import { EmptyState } from "@/components/g8/_foundation/empty-state";
11
- import { useG8Query } from "@/components/g8/_foundation/hooks/use-g8-query";
12
- import { g8Get } from "@/components/g8/_foundation/lib/g8-client";
5
+ import { RecordMeetingsTab } from "@/components/g8/appointments/record-meetings-tab";
13
6
  import { ContactsScreen } from "@/components/g8/crm/contacts-screen";
14
- import { dataOf, formatMoney } from "@/components/g8/deals/lib/deals-types";
15
- import { EnrollDialog } from "@/components/g8/sequencer/enroll-dialog";
16
- import { listOf, statusGroup, type SequenceRow } from "@/components/g8/sequencer/lib/sequencer-utils";
17
-
18
- /** Every active sequence, paging through the whole list (the API answers one page at a time). */
19
- async function activeSequences(signal: AbortSignal): Promise<SequenceRow[]> {
20
- const out: SequenceRow[] = [];
21
- for (let page = 1; page <= 50; page++) {
22
- const env = await g8Get("/sequences", { page, limit: 100 }, { signal });
23
- const rows = listOf<SequenceRow>(env);
24
- out.push(...rows.filter((s) => statusGroup(s.status) === "live"));
25
- const more = (env as { pagination?: { has_next?: boolean } }).pagination?.has_next;
26
- if (!more || rows.length === 0) break;
27
- }
28
- return out;
29
- }
30
-
31
- /** Pick a sequence, then enroll the contacts in it. The enroll dialog shows the sending preflight before anything is sent. */
32
- function AddToSequence({ contactIds, onEnrolled, variant = "outline" }: { contactIds: number[]; onEnrolled?: () => void; variant?: "outline" | "default" }) {
33
- const [step, setStep] = useState<"closed" | "pick" | "enroll">("closed");
34
- const [sequenceId, setSequenceId] = useState("");
35
- const sequences = useG8Query(activeSequences, [], { enabled: step === "pick" });
36
- const chosen = (sequences.data ?? []).find((s) => s.id === sequenceId);
37
- return (
38
- <>
39
- <Button size="sm" variant={variant} disabled={contactIds.length === 0} onClick={() => { setSequenceId(""); setStep("pick"); }}>
40
- <ListPlus className="mr-1 size-4" aria-hidden />
41
- Add to sequence
42
- </Button>
43
- <Sheet open={step === "pick"} onOpenChange={(o) => { if (!o) setStep("closed"); }}>
44
- <SheetContent className="w-full sm:max-w-md">
45
- <SheetHeader>
46
- <SheetTitle>Add to sequence</SheetTitle>
47
- <SheetDescription>{contactIds.length === 1 ? "1 contact" : `${contactIds.length} contacts`} will be enrolled in the sequence you pick.</SheetDescription>
48
- </SheetHeader>
49
- <div className="space-y-3 p-4">
50
- {sequences.error ? <ApiError error={sequences.error} title="Could not load sequences" onRetry={() => void sequences.refetch()} /> : null}
51
- {sequences.loading && !sequences.data ? <Skeleton className="h-9 w-full" aria-label="Loading sequences" /> : null}
52
- {sequences.data && sequences.data.length === 0 ? <EmptyState compact title="No active sequences" description="Launch a sequence on the Sequences page first." /> : null}
53
- {sequences.data && sequences.data.length > 0 ? (
54
- <>
55
- <label htmlFor="enroll-sequence" className="text-sm font-medium">Sequence</label>
56
- <select id="enroll-sequence" className="h-9 w-full rounded-md border bg-background px-2 text-sm" value={sequenceId} onChange={(e) => setSequenceId(e.target.value)}>
57
- <option value="">Choose a sequence</option>
58
- {sequences.data.map((s) => <option key={s.id} value={s.id}>{s.name || s.id}</option>)}
59
- </select>
60
- <Button disabled={!sequenceId} onClick={() => setStep("enroll")}>Continue</Button>
61
- </>
62
- ) : null}
63
- </div>
64
- </SheetContent>
65
- </Sheet>
66
- {step === "enroll" && chosen ? (
67
- <EnrollDialog open sequenceId={chosen.id} sequenceName={chosen.name ?? undefined} contactIds={contactIds} onClose={() => setStep("closed")} onEnrolled={() => { setStep("closed"); onEnrolled?.(); }} />
68
- ) : null}
69
- </>
70
- );
71
- }
72
-
73
- /** One row of GET /contacts/{id}/deals and GET /companies/{id}/deals (the API's ContactDealResponse). */
74
- interface LinkedDeal { deal_id?: string | null; name?: string | null; stage?: string | null; value?: number | null; currency?: string | null; role?: string | null }
75
-
76
- /** The deals linked to one contact or company, each opening in the Deals page. */
77
- function LinkedDeals({ kind, id }: { kind: "contacts" | "companies"; id: number }) {
78
- const q = useG8Query(async (signal) => {
79
- const inner = dataOf<{ items?: LinkedDeal[] } | LinkedDeal[]>(await g8Get(`/${kind}/${id}/deals`, undefined, { signal }));
80
- return (Array.isArray(inner) ? inner : (inner.items ?? [])).filter((d) => d.deal_id);
81
- }, [kind, id]);
82
- if (q.error) return <ApiError error={q.error} title="Could not load deals" onRetry={() => void q.refetch()} />;
83
- if (!q.data) return <Skeleton className="h-24 w-full" aria-label="Loading deals" />;
84
- if (q.data.length === 0) return <EmptyState compact icon={<Handshake className="size-8" />} title="No deals yet" description="Deals linked to this record show up here." />;
85
- return (
86
- <ul className="divide-y rounded-md border" aria-label="Deals">
87
- {q.data.map((d) => (
88
- <li key={d.deal_id}>
89
- <Link href={`/deals?id=${encodeURIComponent(d.deal_id as string)}`} className="flex items-center justify-between gap-3 p-3 text-sm hover:bg-muted">
90
- <span className="min-w-0 truncate font-medium">{d.name || "Untitled deal"}</span>
91
- <span className="shrink-0 text-xs text-muted-foreground">{[d.stage, d.value != null ? formatMoney(d.value, d.currency) : null].filter(Boolean).join(" · ")}</span>
92
- </Link>
93
- </li>
94
- ))}
95
- </ul>
96
- );
97
- }
7
+ import { RecordEngagementTab } from "@/components/g8/crm/record-engagement-tab";
8
+ import { RecordDealsTab } from "@/components/g8/deals/record-deals-tab";
9
+ import { RecordConversationsTab } from "@/components/g8/inbox/record-conversations-tab";
10
+ import { AddToListButton } from "@/components/g8/lists/add-to-list-button";
11
+ import { RecordListsTab } from "@/components/g8/lists/record-lists-tab";
12
+ import { RecordQuotesTab } from "@/components/g8/quotes/record-quotes-tab";
13
+ import { AddToSequenceButton } from "@/components/g8/sequencer/add-to-sequence-button";
14
+ import { RecordSequencesTab } from "@/components/g8/sequencer/record-sequences-tab";
15
+ import { useRouter } from "next/navigation";
98
16
 
99
17
  export default function Page() {
18
+ const router = useRouter();
100
19
  return (
101
20
  <ContactsScreen
102
- renderBulkActions={({ ids, clear }) => <AddToSequence contactIds={ids} onEnrolled={clear} />}
21
+ onOpenCompany={(id) => router.push(`/companies?id=${id}`)}
22
+ renderBulkActions={({ ids, clear }) => (
23
+ <>
24
+ <AddToSequenceButton contactIds={ids} onEnrolled={clear} />
25
+ <AddToListButton contactIds={ids} onAdded={clear} />
26
+ </>
27
+ )}
103
28
  renderDetailActions={(c) => (
104
29
  <>
105
- <AddToSequence contactIds={[c.id]} />
30
+ <AddToSequenceButton contactIds={[c.id]} />
31
+ <AddToListButton contactIds={[c.id]} />
106
32
  </>
107
33
  )}
108
- extraDetailTabs={[{ id: "deals", label: "Deals", render: (c) => <LinkedDeals kind="contacts" id={c.id} /> }]}
34
+ extraDetailTabs={[
35
+ { id: "lists", label: "Lists", render: (c) => <RecordListsTab contactId={c.id} onOpenList={(id) => router.push(`/lists?id=${id}`)} /> },
36
+ { id: "sequences", label: "Sequences", render: (c) => <RecordSequencesTab contactId={c.id} onOpenSequence={(id) => router.push(`/sequences?id=${encodeURIComponent(id)}`)} /> },
37
+ { id: "meetings", label: "Meetings", render: (c) => <RecordMeetingsTab contactId={c.id} onOpenMeeting={(sel) => router.push(`/meetings?sel=${encodeURIComponent(sel)}`)} /> },
38
+ { id: "quotes", label: "Quotes", render: (c) => <RecordQuotesTab kind="contacts" id={c.id} onOpenQuote={(id) => router.push(`/quotes?id=${encodeURIComponent(id)}`)} /> },
39
+ { id: "deals", label: "Deals", render: (c) => <RecordDealsTab kind="contacts" id={c.id} onOpenDeal={(id) => router.push(`/deals?id=${encodeURIComponent(id)}`)} /> },
40
+ { id: "conversations", label: "Conversations", render: (c) => <RecordConversationsTab email={c.work_email} alsoEmails={[c.personal_emails]} onOpenThread={(sel) => router.push(`/inbox?id=${encodeURIComponent(sel)}`)} /> },
41
+ { id: "engagement", label: "Engagement", render: (c) => <RecordEngagementTab kind="contacts" id={c.id} /> },
42
+ ]}
109
43
  />
110
44
  );
111
45
  }
@@ -4,8 +4,17 @@
4
4
  // other blocks of this app plugged into its slots. Edit freely: this file is yours.
5
5
  import { useRouter } from "next/navigation";
6
6
  import { DealsScreen } from "@/components/g8/deals/deals-screen";
7
+ import { CreateQuoteFromDeal } from "@/components/g8/quotes/create-quote-from-deal";
7
8
 
9
+ /** A deal opens its quotes, its contacts and (from a contact) their company. */
8
10
  export default function Page() {
9
11
  const router = useRouter();
10
- return <DealsScreen onOpenQuote={(quoteId) => router.push(`/quotes?id=${encodeURIComponent(quoteId)}`)} />;
12
+ return (
13
+ <DealsScreen
14
+ onOpenQuote={(quoteId) => router.push(`/quotes?id=${encodeURIComponent(quoteId)}`)}
15
+ renderQuoteActions={(deal) => <CreateQuoteFromDeal dealId={deal.id} />}
16
+ onOpenContact={(id) => router.push(`/contacts?id=${id}`)}
17
+ onOpenCompany={(id) => router.push(`/companies?id=${id}`)}
18
+ />
19
+ );
11
20
  }
@@ -10,6 +10,7 @@ import { ApiError } from "@/components/g8/_foundation/api-error";
10
10
  import { EmptyState } from "@/components/g8/_foundation/empty-state";
11
11
  import { useG8Query } from "@/components/g8/_foundation/hooks/use-g8-query";
12
12
  import { g8Get } from "@/components/g8/_foundation/lib/g8-client";
13
+ import { ContactLookupLink } from "@/components/g8/crm/contact-lookup-link";
13
14
  import { DealDetail } from "@/components/g8/deals/deal-detail";
14
15
  import { useDefaultOwner } from "@/components/g8/deals/hooks/use-default-owner";
15
16
  import { InboxScreen } from "@/components/g8/inbox/inbox-screen";
@@ -88,5 +89,15 @@ function CreateDeal({ thread }: { thread: InboxThread }) {
88
89
  }
89
90
 
90
91
  export default function Page() {
91
- return <InboxScreen renderDetailActions={(thread) => <CreateDeal thread={thread} />} />;
92
+ const router = useRouter();
93
+ return (
94
+ <InboxScreen
95
+ renderDetailActions={(thread) => (
96
+ <>
97
+ <ContactLookupLink email={thread.contact?.email} onOpen={(id) => router.push(`/contacts?id=${id}`)} />
98
+ <CreateDeal thread={thread} />
99
+ </>
100
+ )}
101
+ />
102
+ );
92
103
  }
@@ -0,0 +1,23 @@
1
+ "use client";
2
+
3
+ // Generated by `graph8-sdk create {{stackId}}`. The {{block}} block's {{component}} (source in {{blockDir}}), with the
4
+ // other blocks of this app plugged into its slots. Edit freely: this file is yours.
5
+ import { useRouter } from "next/navigation";
6
+ import { Button } from "@graph8/sdk/ui";
7
+ import { Building2, UserRound } from "lucide-react";
8
+ import { LifecycleScreen } from "@/components/g8/lifecycle/lifecycle-screen";
9
+
10
+ /** A lifecycle record opens its company or contact record. */
11
+ export default function Page() {
12
+ const router = useRouter();
13
+ return (
14
+ <LifecycleScreen
15
+ renderDetailActions={(record) => (
16
+ <Button size="sm" variant="outline" onClick={() => router.push(`/${record.kind === "company" ? "companies" : "contacts"}?id=${record.id}`)}>
17
+ {record.kind === "company" ? <Building2 className="mr-1 size-4" aria-hidden /> : <UserRound className="mr-1 size-4" aria-hidden />}
18
+ {record.kind === "company" ? "Open company" : "Open contact"}
19
+ </Button>
20
+ )}
21
+ />
22
+ );
23
+ }
@@ -0,0 +1,12 @@
1
+ "use client";
2
+
3
+ // Generated by `graph8-sdk create {{stackId}}`. The {{block}} block's {{component}} (source in {{blockDir}}), with the
4
+ // other blocks of this app plugged into its slots. Edit freely: this file is yours.
5
+ import { useRouter } from "next/navigation";
6
+ import { ListsScreen } from "@/components/g8/lists/lists-screen";
7
+
8
+ /** A list member opens in Contacts. */
9
+ export default function Page() {
10
+ const router = useRouter();
11
+ return <ListsScreen onOpenContact={(id) => router.push(`/contacts?id=${id}`)} />;
12
+ }
@@ -0,0 +1,13 @@
1
+ "use client";
2
+
3
+ // Generated by `graph8-sdk create {{stackId}}`. The {{block}} block's {{component}} (source in {{blockDir}}), with the
4
+ // other blocks of this app plugged into its slots. Edit freely: this file is yours.
5
+ import { useRouter } from "next/navigation";
6
+ import { MeetingContactLinks } from "@/components/g8/appointments/meeting-contact-links";
7
+ import { MeetingsScreen } from "@/components/g8/appointments/meetings-screen";
8
+
9
+ /** A meeting opens the attendees who are contacts in your CRM. */
10
+ export default function Page() {
11
+ const router = useRouter();
12
+ return <MeetingsScreen renderDetailActions={(selection) => <MeetingContactLinks selection={selection} onOpenContact={(id) => router.push(`/contacts?id=${id}`)} />} />;
13
+ }
@@ -0,0 +1,12 @@
1
+ "use client";
2
+
3
+ // Generated by `graph8-sdk create {{stackId}}`. The {{block}} block's {{component}} (source in {{blockDir}}), with the
4
+ // other blocks of this app plugged into its slots. Edit freely: this file is yours.
5
+ import { useRouter } from "next/navigation";
6
+ import { SequencesScreen } from "@/components/g8/sequencer/sequences-screen";
7
+
8
+ /** An enrolled person opens in Contacts. */
9
+ export default function Page() {
10
+ const router = useRouter();
11
+ return <SequencesScreen onOpenContact={(id) => router.push(`/contacts?id=${id}`)} />;
12
+ }
@@ -0,0 +1,20 @@
1
+ "use client";
2
+
3
+ // Generated by `graph8-sdk create {{stackId}}`. The {{block}} block's {{component}} (source in {{blockDir}}), with the
4
+ // other blocks of this app plugged into its slots. Edit freely: this file is yours.
5
+ import { useRouter } from "next/navigation";
6
+ import { TasksScreen } from "@/components/g8/crm/tasks-screen";
7
+
8
+ /** A task's linked record opens in the screen that owns it. */
9
+ export default function Page() {
10
+ const router = useRouter();
11
+ return (
12
+ <TasksScreen
13
+ onOpenRecord={(record) => {
14
+ if (record.entity_type === "contact") router.push(`/contacts?id=${encodeURIComponent(record.entity_id)}`);
15
+ if (record.entity_type === "company") router.push(`/companies?id=${encodeURIComponent(record.entity_id)}`);
16
+ if (record.entity_type === "deal") router.push(`/deals?id=${encodeURIComponent(record.entity_id)}`);
17
+ }}
18
+ />
19
+ );
20
+ }
@@ -6,6 +6,7 @@
6
6
  "status": "available",
7
7
  "blocks": [
8
8
  "foundation",
9
+ "pickers",
9
10
  "crm",
10
11
  "objects",
11
12
  "lists",
@@ -17,6 +18,7 @@
17
18
  "inbox",
18
19
  "newsletter",
19
20
  "nurture",
21
+ "surveys",
20
22
  "webchat",
21
23
  "appointments",
22
24
  "pages",
@@ -65,7 +67,8 @@
65
67
  "component": "ListsScreen",
66
68
  "icon": "ListChecks",
67
69
  "group": "Prospect",
68
- "description": "Saved audiences you can sequence or sync"
70
+ "description": "Saved audiences you can sequence or sync",
71
+ "page": "pages/lists.tsx.tmpl"
69
72
  },
70
73
  {
71
74
  "label": "Visitors",
@@ -102,7 +105,8 @@
102
105
  "component": "SequencesScreen",
103
106
  "icon": "Workflow",
104
107
  "group": "Engage",
105
- "description": "Multi-step outreach cadences"
108
+ "description": "Multi-step outreach cadences",
109
+ "page": "pages/sequences.tsx.tmpl"
106
110
  },
107
111
  {
108
112
  "label": "Meetings",
@@ -111,7 +115,8 @@
111
115
  "component": "MeetingsScreen",
112
116
  "icon": "CalendarCheck",
113
117
  "group": "Engage",
114
- "description": "Booked, held and missed meetings"
118
+ "description": "Booked, held and missed meetings",
119
+ "page": "pages/meetings.tsx.tmpl"
115
120
  },
116
121
  {
117
122
  "label": "Scheduling",
@@ -149,6 +154,15 @@
149
154
  "group": "Marketing",
150
155
  "description": "Automated nurture tracks"
151
156
  },
157
+ {
158
+ "label": "Surveys",
159
+ "path": "/surveys",
160
+ "block": "surveys",
161
+ "component": "SurveysScreen",
162
+ "icon": "ClipboardCheck",
163
+ "group": "Marketing",
164
+ "description": "NPS and CSAT: ask, score and read the answers"
165
+ },
152
166
  {
153
167
  "label": "Forms",
154
168
  "path": "/forms",
@@ -212,7 +226,8 @@
212
226
  "component": "LifecycleScreen",
213
227
  "icon": "GitBranch",
214
228
  "group": "Pipeline",
215
- "description": "Move records through lifecycle stages"
229
+ "description": "Move records through lifecycle stages",
230
+ "page": "pages/lifecycle.tsx.tmpl"
216
231
  },
217
232
  {
218
233
  "label": "Tasks",
@@ -221,7 +236,8 @@
221
236
  "component": "TasksScreen",
222
237
  "icon": "CheckSquare",
223
238
  "group": "Work",
224
- "description": "Follow-ups due across your records"
239
+ "description": "Follow-ups due across your records",
240
+ "page": "pages/tasks.tsx.tmpl"
225
241
  },
226
242
  {
227
243
  "label": "Workflows",