@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,148 @@
1
+ "use client";
2
+
3
+ /**
4
+ * DomainDetail: one sending domain, complete. Every field, the mailboxes on it, and every action: connect it
5
+ * to mailbox provisioning, check DNS propagation, buy mailboxes on it.
6
+ *
7
+ * SDK operations, in order:
8
+ * 1. listProviderDomains GET /provider-domains (read; the row for this domain)
9
+ * 2. listMailboxes GET /mailboxes (read; mailboxes whose address ends with the domain)
10
+ * 3. connectProvider POST /provider-domains/{domain_id}/connect-provider (billable tier: confirmed)
11
+ * 4. checkDomainPropagation POST /provider-domains/{domain_id}/check-propagation (billable tier: confirmed)
12
+ * Buying mailboxes is the ConnectMailbox "Buy" tab, opened by `onBuyMailboxes` (confirmed with a credit estimate there).
13
+ *
14
+ * Tiers: 3 and 4 are billable in the contract (no credit estimate is known), so each opens ConfirmSpendDialog.
15
+ */
16
+
17
+ import { useState } from "react";
18
+ import type { ReactNode } from "react";
19
+ import { Button, Skeleton } from "@graph8/sdk/ui";
20
+ import { ApiError } from "@/g8/components/api-error";
21
+ import { FirstNotice } from "@/g8/components/paging-notices";
22
+ import { ConfirmSpendDialog } from "@/g8/components/confirm-spend-dialog";
23
+ import { DetailPanel } from "@/g8/components/screen/detail-panel";
24
+ import { KeyValueList } from "@/g8/components/screen/key-value-list";
25
+ import { SectionCard } from "@/g8/components/screen/section-card";
26
+ import { StatusPill } from "@/g8/components/screen/status-pill";
27
+ import { useG8Mutation } from "@/g8/hooks/use-g8-mutation";
28
+ import { useG8Query } from "@/g8/hooks/use-g8-query";
29
+ import { g8Get, g8Post } from "@/g8/lib/g8-client";
30
+ import { fieldItems, listOf, objectOf } from "../lib/mailboxes-utils";
31
+ import { useProviderDomains } from "../lib/use-provider-domains";
32
+ import type { DomainRow, MailboxRow } from "../lib/mailboxes-utils";
33
+
34
+ export interface DomainDetailProps {
35
+ domainId: string | number;
36
+ onClose?: () => void;
37
+ /** Full-page mode: show an "Open full page" (onExpand) or "Back to split view" (onCollapse) button. */
38
+ onExpand?: () => void;
39
+ onCollapse?: () => void;
40
+ /** Called after a connect so a list can refresh. */
41
+ onChanged?: () => void;
42
+ /** Open the Buy tab of ConnectMailbox for this domain (a screen shows it in a sheet). */
43
+ onBuyMailboxes?: (domain: DomainRow) => void;
44
+ onOpenMailbox?: (mailbox: MailboxRow) => void;
45
+ renderActions?: (domain: DomainRow) => ReactNode;
46
+ className?: string;
47
+ }
48
+
49
+ type Pending = "connect" | "propagation";
50
+
51
+ /** The mailboxes API has no paging: a full read is announced where the mailboxes are listed. */
52
+ const MAILBOX_LIMIT = 200;
53
+
54
+ export function DomainDetail({ domainId, onClose, onExpand, onCollapse, onChanged, onBuyMailboxes, onOpenMailbox, renderActions, className }: DomainDetailProps) {
55
+ const [pending, setPending] = useState<Pending | null>(null);
56
+ const [note, setNote] = useState<string | null>(null);
57
+ const domains = useProviderDomains([domainId]);
58
+ const mailboxes = useG8Query((signal) => g8Get("/mailboxes", { limit: MAILBOX_LIMIT }, { signal }), [domainId]);
59
+
60
+ const row = domains.items.find((d) => String(d.id) === String(domainId));
61
+ const run = useG8Mutation(async (p: Pending) => {
62
+ if (p === "connect") {
63
+ await g8Post(`/provider-domains/${domainId}/connect-provider`, {});
64
+ setNote(`${row?.domain ?? "The domain"} is connecting. Check propagation in a few minutes.`);
65
+ await domains.refetch();
66
+ onChanged?.();
67
+ } else {
68
+ const status = objectOf(await g8Post(`/provider-domains/${domainId}/check-propagation`, {}));
69
+ setNote(status.propagated ? `${row?.domain} has propagated.` : `${row?.domain} has not propagated yet.`);
70
+ }
71
+ setPending(null);
72
+ }, { onError: () => setPending(null) });
73
+
74
+ if (domains.error) return <ApiError error={domains.error} title="Could not load the domain" onRetry={() => void domains.refetch()} className={className} />;
75
+ if (domains.loading && !domains.loaded) return <Skeleton className={`h-48 w-full ${className ?? ""}`} />;
76
+ if (!row) return <p className={`p-4 text-sm ${className ?? ""}`}>This domain no longer exists.</p>;
77
+
78
+ const onDomain = listOf<MailboxRow>(mailboxes.data).filter((m) => (m.email ?? "").toLowerCase().endsWith(`@${row.domain.toLowerCase()}`));
79
+ return (
80
+ <DetailPanel
81
+ className={className}
82
+ title={row.domain}
83
+ subtitle={row.source ?? undefined}
84
+ badges={
85
+ <>
86
+ <StatusPill tone={row.provider_connected ? "positive" : "warning"} dot>{row.provider_connected ? "Connected" : "Not connected"}</StatusPill>
87
+ {row.status ? <StatusPill tone="neutral">{row.status}</StatusPill> : null}
88
+ </>
89
+ }
90
+ actions={
91
+ <>
92
+ {!row.provider_connected ? <Button size="sm" variant="outline" onClick={() => setPending("connect")}>Connect domain</Button> : null}
93
+ <Button size="sm" variant="outline" onClick={() => setPending("propagation")}>Check DNS</Button>
94
+ <Button size="sm" disabled={!row.provider_connected || !onBuyMailboxes} onClick={() => onBuyMailboxes?.(row)}>Buy mailboxes</Button>
95
+ {renderActions?.(row)}
96
+ <ConfirmSpendDialog
97
+ open={pending !== null}
98
+ tier="billable"
99
+ title={pending === "connect" ? `Connect ${row.domain}` : `Check DNS propagation for ${row.domain}`}
100
+ description={pending === "connect" ? "Connects the domain to mailbox provisioning. Required before buying mailboxes on it." : "Asks the provider whether the nameservers have propagated."}
101
+ confirmLabel={pending === "connect" ? "Connect domain" : "Check propagation"}
102
+ confirming={run.loading}
103
+ onCancel={() => setPending(null)}
104
+ onConfirm={() => pending && void run.mutate(pending)}
105
+ />
106
+ </>
107
+ }
108
+ summary={note ? <p role="status" className="text-sm">{note}</p> : undefined}
109
+ onClose={onClose}
110
+ onExpand={onExpand}
111
+ onCollapse={onCollapse}
112
+ tabs={[
113
+ {
114
+ id: "details",
115
+ label: "Details",
116
+ content: (
117
+ <div className="space-y-4">
118
+ {run.error ? <ApiError error={run.error} onRetry={run.reset} /> : null}
119
+ <KeyValueList columns={2} items={fieldItems(row as unknown as Record<string, unknown>)} />
120
+ </div>
121
+ ),
122
+ },
123
+ {
124
+ id: "mailboxes",
125
+ label: "Mailboxes",
126
+ count: onDomain.length,
127
+ content: (
128
+ <SectionCard title="Mailboxes on this domain" description="Open one for warmup and health.">
129
+ {onDomain.length === 0 ? (
130
+ <p className="text-sm text-muted-foreground">{row.provider_connected ? "No mailboxes yet. Buy some with the button above." : "Connect the domain first, then buy mailboxes on it."}</p>
131
+ ) : (
132
+ <ul className="divide-y">
133
+ {onDomain.map((m) => (
134
+ <li key={m.id} className="flex items-center justify-between py-2 text-sm">
135
+ <Button variant="ghost" size="sm" onClick={() => onOpenMailbox?.(m)}>{m.email}</Button>
136
+ <StatusPill tone={m.connection_status === "active" ? "positive" : "warning"} dot>{m.connection_status ?? "unknown"}</StatusPill>
137
+ </li>
138
+ ))}
139
+ </ul>
140
+ )}
141
+ <FirstNotice shown={listOf<MailboxRow>(mailboxes.data).length} limit={MAILBOX_LIMIT} noun="mailboxes" />
142
+ </SectionCard>
143
+ ),
144
+ },
145
+ ]}
146
+ />
147
+ );
148
+ }
@@ -24,10 +24,14 @@ import { g8Get, g8Post } from "@/g8/lib/g8-client";
24
24
  import { useG8Query } from "@/g8/hooks/use-g8-query";
25
25
  import { useG8Mutation } from "@/g8/hooks/use-g8-mutation";
26
26
  import { ApiError } from "@/g8/components/api-error";
27
+ import { FirstNotice } from "@/g8/components/paging-notices";
27
28
  import { ConfirmSpendDialog } from "@/g8/components/confirm-spend-dialog";
28
29
  import { EmptyState } from "@/g8/components/empty-state";
29
30
  import { DEFAULT_DOMAIN_CREDITS, listOf, newIdempotencyKey, objectOf, statusClass } from "../lib/mailboxes-utils";
31
+ import { useProviderDomains } from "../lib/use-provider-domains";
30
32
  import type { DomainRow } from "../lib/mailboxes-utils";
33
+ import { plural } from "@/g8/lib/plural";
34
+ import { useBrand } from "@/g8/hooks/use-brand";
31
35
 
32
36
  export interface DomainPurchaseProps {
33
37
  /** Called after a purchase was accepted (provisioning continues in the background). */
@@ -54,6 +58,7 @@ function suggestionsOf(envelope: unknown): string[] {
54
58
  }
55
59
 
56
60
  export function DomainPurchase({ onPurchased, className }: DomainPurchaseProps) {
61
+ const brand = useBrand();
57
62
  const [keyword, setKeyword] = useState("");
58
63
  const [names, setNames] = useState<string[]>([]);
59
64
  const [selected, setSelected] = useState<string[]>([]);
@@ -63,7 +68,7 @@ export function DomainPurchase({ onPurchased, className }: DomainPurchaseProps)
63
68
  const [note, setNote] = useState<string | null>(null);
64
69
  const idemKey = useRef<{ sig: string; key: string } | null>(null);
65
70
 
66
- const domains = useG8Query((signal) => g8Get("/provider-domains", { page: 1, limit: 50 }, { signal }), []);
71
+ const domains = useProviderDomains([]);
67
72
  const suggest = useG8Mutation(async () => {
68
73
  setNames(suggestionsOf(await g8Post("/provider-domains/generate-domains", { keyword: keyword.trim(), count: 10 })));
69
74
  setSelected([]);
@@ -103,13 +108,13 @@ export function DomainPurchase({ onPurchased, className }: DomainPurchaseProps)
103
108
  const toggle = (d: string) => setSelected((s) => (s.includes(d) ? s.filter((x) => x !== d) : [...s, d]));
104
109
  const buyable = selected.filter((d) => avail[d]?.available);
105
110
  const contactOk = contact.first_name.trim() && contact.last_name.trim() && /\S+@\S+/.test(contact.email);
106
- const rows = listOf<DomainRow>(domains.data);
111
+ const rows = domains.items;
107
112
 
108
113
  const dialog = (() => {
109
114
  if (!pending) return null;
110
115
  if (pending.kind === "check")
111
116
  return {
112
- title: `Check ${pending.domains.length} domain${pending.domains.length === 1 ? "" : "s"}`,
117
+ title: `Check ${plural(pending.domains.length, "domain")}`,
113
118
  description: "Looks up availability and price. The API documents no charge for this check.",
114
119
  credits: 0,
115
120
  label: "Check availability",
@@ -138,8 +143,8 @@ export function DomainPurchase({ onPurchased, className }: DomainPurchaseProps)
138
143
 
139
144
  return (
140
145
  <div className={`space-y-5 ${className ?? ""}`}>
141
- <section className="space-y-2 rounded border border-gray-200 p-3">
142
- <h3 className="text-sm font-semibold">Find a domain</h3>
146
+ <section className="space-y-2 rounded border border-border p-3">
147
+ <h3 className="text-sm font-medium">Find a domain</h3>
143
148
  <form
144
149
  className="flex gap-2"
145
150
  onSubmit={(e) => {
@@ -162,7 +167,7 @@ export function DomainPurchase({ onPurchased, className }: DomainPurchaseProps)
162
167
  {d}
163
168
  {avail[d] ? (
164
169
  <span
165
- className={`rounded px-1.5 text-xs ${avail[d].available ? "bg-green-100 text-green-800" : "bg-red-100 text-red-800"}`}
170
+ className={`rounded px-1.5 text-xs ${avail[d].available ? "bg-positive text-positive-foreground" : "bg-error text-error-foreground"}`}
166
171
  >
167
172
  {avail[d].available
168
173
  ? `available${avail[d].price != null ? ` ${avail[d].price}` : ""}`
@@ -186,8 +191,8 @@ export function DomainPurchase({ onPurchased, className }: DomainPurchaseProps)
186
191
  </Button>
187
192
  </section>
188
193
 
189
- <section className="space-y-2 rounded border border-gray-200 p-3">
190
- <h3 className="text-sm font-semibold">Registrant</h3>
194
+ <section className="space-y-2 rounded border border-border p-3">
195
+ <h3 className="text-sm font-medium">Registrant</h3>
191
196
  <div className="grid gap-2 sm:grid-cols-3">
192
197
  <Input
193
198
  aria-label="First name"
@@ -209,12 +214,12 @@ export function DomainPurchase({ onPurchased, className }: DomainPurchaseProps)
209
214
  />
210
215
  </div>
211
216
  <Button disabled={buyable.length === 0 || !contactOk} onClick={() => setPending({ kind: "buy", domains: buyable })}>
212
- Buy {buyable.length} domain{buyable.length === 1 ? "" : "s"}
217
+ Buy {plural(buyable.length, "domain")}
213
218
  </Button>
214
219
  </section>
215
220
 
216
221
  {note ? (
217
- <p role="status" className="text-sm text-gray-700">
222
+ <p role="status" className="text-sm text-foreground">
218
223
  {note}
219
224
  </p>
220
225
  ) : null}
@@ -223,18 +228,18 @@ export function DomainPurchase({ onPurchased, className }: DomainPurchaseProps)
223
228
  <section aria-label="Your domains">
224
229
  {domains.error ? (
225
230
  <ApiError error={domains.error} onRetry={() => void domains.refetch()} />
226
- ) : domains.loading && !domains.data ? (
231
+ ) : domains.loading && !domains.loaded ? (
227
232
  <Skeleton className="h-16 w-full" />
228
233
  ) : rows.length === 0 ? (
229
- <EmptyState title="No sending domains yet" description="Buy one above, or add a domain you already own in the graph8 app." />
234
+ <EmptyState title="No sending domains yet" description={`Buy one above, or add a domain you already own in the ${brand.linkLabel} app.`} />
230
235
  ) : (
231
- <ul className="divide-y rounded border border-gray-200">
236
+ <ul className="divide-y rounded border border-border">
232
237
  {rows.map((d) => (
233
238
  <li key={d.id} className="flex flex-wrap items-center justify-between gap-2 px-3 py-2 text-sm">
234
239
  <span>
235
240
  <span className="font-medium">{d.domain}</span>{" "}
236
241
  <span className={`rounded px-1.5 text-xs ${statusClass(d.status)}`}>{d.status ?? "unknown"}</span>{" "}
237
- <span className="text-xs text-gray-500">{d.mailbox_count ?? 0} mailboxes</span>
242
+ <span className="text-xs text-muted-foreground">{d.mailbox_count ?? 0} mailboxes</span>
238
243
  </span>
239
244
  <span className="flex gap-1">
240
245
  {!d.provider_connected && !d.is_external ? (
@@ -251,6 +256,7 @@ export function DomainPurchase({ onPurchased, className }: DomainPurchaseProps)
251
256
  ))}
252
257
  </ul>
253
258
  )}
259
+ <FirstNotice shown={rows.length} limit={rows.length} force={domains.truncated} noun="domains" />
254
260
  </section>
255
261
 
256
262
  {pending && dialog ? (
@@ -0,0 +1,157 @@
1
+ "use client";
2
+
3
+ /**
4
+ * MailboxDetail: one mailbox, complete. Every field the API returns, the domain it sits on, its warmup and
5
+ * deliverability, and every action: test the connection, archive or restore, delete.
6
+ *
7
+ * SDK operations, in order:
8
+ * 1. getMailbox GET /mailboxes/{mailbox_id} (read; all fields)
9
+ * 2. listProviderDomains GET /provider-domains (read; finds the domain this address sits on)
10
+ * 3. testMailboxConnection POST /mailboxes/{mailbox_id}/test-connection (write; SMTP and IMAP, no spend)
11
+ * 4. archiveMailbox POST /mailboxes/{mailbox_id}/archive (destructive: confirmed; `is_archived: false` restores)
12
+ * 5. deleteMailbox DELETE /mailboxes/{mailbox_id} (destructive: confirmed)
13
+ * Warmup tab: WarmupHealth (analytics, start/stop warmup, confirmed placement test).
14
+ *
15
+ * Tiers: 4 and 5 are destructive, so each opens ConfirmSpendDialog. Credentials are write-only and never shown.
16
+ */
17
+
18
+ import { useState } from "react";
19
+ import type { ReactNode } from "react";
20
+ import { Button, Skeleton } from "@graph8/sdk/ui";
21
+ import { ApiError } from "@/g8/components/api-error";
22
+ import { ConfirmSpendDialog } from "@/g8/components/confirm-spend-dialog";
23
+ import { DetailPanel } from "@/g8/components/screen/detail-panel";
24
+ import { EntityAvatar } from "@/g8/components/screen/entity-avatar";
25
+ import { KeyValueList } from "@/g8/components/screen/key-value-list";
26
+ import { SectionCard } from "@/g8/components/screen/section-card";
27
+ import { StatusPill } from "@/g8/components/screen/status-pill";
28
+ import { useG8Mutation } from "@/g8/hooks/use-g8-mutation";
29
+ import { useG8Query } from "@/g8/hooks/use-g8-query";
30
+ import { g8Delete, g8Get, g8Post } from "@/g8/lib/g8-client";
31
+ import { fieldItems, listOf, objectOf } from "../lib/mailboxes-utils";
32
+ import { useProviderDomains } from "../lib/use-provider-domains";
33
+ import type { DomainRow, MailboxRow } from "../lib/mailboxes-utils";
34
+ import { WarmupHealth } from "./warmup-health";
35
+ import { useBrand } from "@/g8/hooks/use-brand";
36
+
37
+ export interface MailboxDetailProps {
38
+ mailboxId: string | number;
39
+ /** Controlled tab ("details" | "warmup" | an extra tab id) and its change handler, for deep links. */
40
+ tab?: string;
41
+ onTabChange?: (tab: string) => void;
42
+ onClose?: () => void;
43
+ /** Full-page mode: show an "Open full page" (onExpand) or "Back to split view" (onCollapse) button. */
44
+ onExpand?: () => void;
45
+ onCollapse?: () => void;
46
+ /** Called after archive, restore or delete so a list can refresh. */
47
+ onChanged?: () => void;
48
+ /** Open the domain this mailbox sits on. */
49
+ onOpenDomain?: (domain: DomainRow) => void;
50
+ renderActions?: (mailbox: MailboxRow) => ReactNode;
51
+ extraTabs?: { id: string; label: string; render: (mailbox: MailboxRow) => ReactNode }[];
52
+ className?: string;
53
+ }
54
+
55
+ type Pending = "archive" | "restore" | "delete";
56
+ interface TestResult { success?: boolean; smtp?: { success?: boolean; error?: string }; imap?: { success?: boolean; error?: string } }
57
+
58
+ export function MailboxDetail({ mailboxId, tab, onTabChange, onClose, onExpand, onCollapse, onChanged, onOpenDomain, renderActions, extraTabs, className }: MailboxDetailProps) {
59
+ const brand = useBrand();
60
+ const [pending, setPending] = useState<Pending | null>(null);
61
+ const [testNote, setTestNote] = useState<string | null>(null);
62
+ const q = useG8Query((signal) => g8Get(`/mailboxes/${mailboxId}`, undefined, { signal }), [mailboxId]);
63
+ const domains = useProviderDomains([]);
64
+
65
+ const test = useG8Mutation(async () => {
66
+ const r = objectOf(await g8Post(`/mailboxes/${mailboxId}/test-connection`, {})) as TestResult;
67
+ setTestNote(
68
+ r.success
69
+ ? "SMTP and IMAP both work"
70
+ : [r.smtp?.success === false && `SMTP: ${r.smtp.error ?? "failed"}`, r.imap?.success === false && `IMAP: ${r.imap.error ?? "failed"}`].filter(Boolean).join("; ") || "Connection failed",
71
+ );
72
+ await q.refetch();
73
+ });
74
+ const act = useG8Mutation(async (p: Pending) => {
75
+ if (p === "delete") await g8Delete(`/mailboxes/${mailboxId}`);
76
+ else await g8Post(`/mailboxes/${mailboxId}/archive`, { is_archived: p === "archive" });
77
+ setPending(null);
78
+ if (p === "delete") onClose?.();
79
+ else await q.refetch();
80
+ onChanged?.();
81
+ }, { onError: () => setPending(null) });
82
+
83
+ if (q.error) return <ApiError error={q.error} title="Could not load the mailbox" onRetry={() => void q.refetch()} className={className} />;
84
+ if (q.loading && !q.data) return <Skeleton className={`h-48 w-full ${className ?? ""}`} />;
85
+ const raw = objectOf(q.data);
86
+ const m = { id: String(mailboxId), email: null, ...raw } as MailboxRow;
87
+ const domain = (m.email ?? "").split("@")[1]?.toLowerCase();
88
+ const domainRow = domains.items.find((d) => d.domain?.toLowerCase() === domain);
89
+ const status = m.connection_status ?? "unknown";
90
+ const name = m.email ?? `Mailbox ${mailboxId}`;
91
+
92
+ return (
93
+ <DetailPanel
94
+ className={className}
95
+ title={name}
96
+ subtitle={[m.display_name, m.provider].filter(Boolean).join(" - ") || undefined}
97
+ avatar={<EntityAvatar name={m.display_name || name} size="lg" />}
98
+ badges={
99
+ <>
100
+ <StatusPill tone={status === "active" ? "positive" : status === "unknown" ? "neutral" : "warning"} dot>{status}</StatusPill>
101
+ {m.is_archived ? <StatusPill tone="neutral">archived</StatusPill> : null}
102
+ </>
103
+ }
104
+ actions={
105
+ <>
106
+ <Button size="sm" variant="outline" loading={test.loading} onClick={() => void test.mutate(undefined)}>Test connection</Button>
107
+ <Button size="sm" variant="outline" onClick={() => setPending(m.is_archived ? "restore" : "archive")}>{m.is_archived ? "Restore mailbox" : "Archive mailbox"}</Button>
108
+ <Button size="sm" variant="outline" onClick={() => setPending("delete")}>Delete mailbox</Button>
109
+ {renderActions?.(m)}
110
+ <ConfirmSpendDialog
111
+ open={pending !== null}
112
+ tier="destructive"
113
+ title={`${pending === "delete" ? "Delete" : pending === "restore" ? "Restore" : "Archive"} ${name}`}
114
+ description={
115
+ pending === "delete" ? "Sequences that send from it can no longer send. This cannot be undone."
116
+ : pending === "restore" ? "It comes back into pickers. Nothing is deleted."
117
+ : "It disappears from pickers. History is kept and you can restore it."
118
+ }
119
+ confirmLabel={pending === "delete" ? "Delete mailbox" : pending === "restore" ? "Restore mailbox" : "Archive mailbox"}
120
+ affected={1}
121
+ confirming={act.loading}
122
+ onCancel={() => setPending(null)}
123
+ onConfirm={() => pending && void act.mutate(pending)}
124
+ />
125
+ </>
126
+ }
127
+ summary={testNote ? <p role="status" className="px-5 py-2 text-sm">{testNote}</p> : undefined}
128
+ onClose={onClose}
129
+ onExpand={onExpand}
130
+ onCollapse={onCollapse}
131
+ activeTab={tab}
132
+ onTabChange={onTabChange}
133
+ tabs={[
134
+ {
135
+ id: "details",
136
+ label: "Details",
137
+ content: (
138
+ <div className="space-y-4">
139
+ {test.error ? <ApiError error={test.error} onRetry={test.reset} /> : null}
140
+ {act.error ? <ApiError error={act.error} onRetry={act.reset} /> : null}
141
+ <KeyValueList columns={2} items={fieldItems(raw)} />
142
+ <SectionCard title="Domain" description="The sending domain this address belongs to.">
143
+ {domainRow ? (
144
+ <Button size="sm" variant="outline" disabled={!onOpenDomain} onClick={() => onOpenDomain?.(domainRow)}>{domainRow.domain}</Button>
145
+ ) : (
146
+ <p className="text-sm text-muted-foreground">{domain ? `${domain} is not a domain bought or connected through ${brand.linkLabel}.` : "No domain."}</p>
147
+ )}
148
+ </SectionCard>
149
+ </div>
150
+ ),
151
+ },
152
+ { id: "warmup", label: "Warmup and health", content: <WarmupHealth mailboxId={mailboxId} showFleet={false} /> },
153
+ ...(extraTabs ?? []).map((t) => ({ id: t.id, label: t.label, content: t.render(m) })),
154
+ ]}
155
+ />
156
+ );
157
+ }
@@ -22,9 +22,13 @@ import { useG8Mutation } from "@/g8/hooks/use-g8-mutation";
22
22
  import { ApiError } from "@/g8/components/api-error";
23
23
  import { ConfirmSpendDialog } from "@/g8/components/confirm-spend-dialog";
24
24
  import { EmptyState } from "@/g8/components/empty-state";
25
+ import { FirstNotice } from "@/g8/components/paging-notices";
25
26
  import { listOf, objectOf, statusClass } from "../lib/mailboxes-utils";
26
27
  import type { MailboxRow } from "../lib/mailboxes-utils";
27
28
 
29
+ /** The read cap. The mailboxes API has no paging, so a full read is announced ("Showing the first 200"). */
30
+ const MAILBOX_LIMIT = 200;
31
+
28
32
  export interface MailboxListProps {
29
33
  includeArchived?: boolean;
30
34
  /** Called when a row is opened (for example to show WarmupHealth for it). */
@@ -47,7 +51,7 @@ export function MailboxList({ includeArchived = false, onSelect, emptyAction, cl
47
51
  const [tests, setTests] = useState<Record<string, string>>({});
48
52
  const [testing, setTesting] = useState<ReadonlySet<string>>(new Set());
49
53
  const list = useG8Query(
50
- (signal) => g8Get("/mailboxes", { limit: 200, include_archived: includeArchived }, { signal }),
54
+ (signal) => g8Get("/mailboxes", { limit: MAILBOX_LIMIT, include_archived: includeArchived }, { signal }),
51
55
  [includeArchived],
52
56
  );
53
57
 
@@ -114,13 +118,13 @@ export function MailboxList({ includeArchived = false, onSelect, emptyAction, cl
114
118
  <button type="button" className="text-left font-medium hover:underline" onClick={() => onSelect?.(m)}>
115
119
  {m.email ?? `Mailbox ${m.id}`}
116
120
  </button>
117
- <div className="text-xs text-gray-500">
121
+ <div className="text-xs text-muted-foreground">
118
122
  {m.display_name ?? ""}
119
123
  {m.provider ? ` - ${m.provider}` : ""}
120
124
  {m.is_archived ? " - archived" : ""}
121
125
  </div>
122
126
  {tests[m.id] ? (
123
- <div role="status" className="text-xs text-gray-700">
127
+ <div role="status" className="text-xs text-foreground">
124
128
  {tests[m.id]}
125
129
  </div>
126
130
  ) : null}
@@ -163,6 +167,7 @@ export function MailboxList({ includeArchived = false, onSelect, emptyAction, cl
163
167
  ))}
164
168
  </TableBody>
165
169
  </Table>
170
+ <FirstNotice shown={rows.length} limit={MAILBOX_LIMIT} noun="mailboxes" />
166
171
  {pending ? (
167
172
  <ConfirmSpendDialog
168
173
  open