@graph8/sdk 0.370.0 → 0.374.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 (646) hide show
  1. package/README.md +22 -3
  2. package/blocks/_foundation/README.md +61 -0
  3. package/blocks/_foundation/block.json +57 -0
  4. package/blocks/_foundation/components/auth-gate.tsx +363 -0
  5. package/blocks/_foundation/components/confirm-spend-dialog.tsx +15 -8
  6. package/blocks/_foundation/components/empty-state.tsx +5 -2
  7. package/blocks/_foundation/components/list-select.tsx +112 -0
  8. package/blocks/_foundation/components/paging-notices.tsx +55 -0
  9. package/blocks/_foundation/components/screen/detail-panel.tsx +2 -1
  10. package/blocks/_foundation/components/screen/filter-controls.tsx +92 -0
  11. package/blocks/_foundation/components/screen/index.ts +1 -0
  12. package/blocks/_foundation/components/screen/split-view.tsx +1 -1
  13. package/blocks/_foundation/hooks/use-all-pages.ts +54 -0
  14. package/blocks/_foundation/hooks/use-load-more-list.ts +61 -0
  15. package/blocks/_foundation/hooks/use-url-filters.ts +93 -0
  16. package/blocks/_foundation/lib/paging.ts +57 -0
  17. package/blocks/_foundation/lib/use-debounced-value.ts +13 -0
  18. package/blocks/_foundation/server/auth.ts +815 -0
  19. package/blocks/agents/README.md +81 -4
  20. package/blocks/agents/block.json +311 -2
  21. package/blocks/agents/components/agent-activity.tsx +112 -0
  22. package/blocks/agents/components/agent-approvals.tsx +135 -0
  23. package/blocks/agents/components/agent-builder.tsx +17 -3
  24. package/blocks/agents/components/agent-conversations.tsx +143 -0
  25. package/blocks/agents/components/agent-knowledge-panel.tsx +2 -2
  26. package/blocks/agents/components/agent-operators.tsx +164 -0
  27. package/blocks/agents/components/agent-run-detail.tsx +20 -3
  28. package/blocks/agents/components/agent-runs.tsx +3 -3
  29. package/blocks/agents/components/agent-skills-panel.tsx +7 -7
  30. package/blocks/agents/components/agent-test-history.tsx +121 -0
  31. package/blocks/agents/components/agents-screen.tsx +53 -11
  32. package/blocks/agents/components/assistant-sessions.tsx +150 -0
  33. package/blocks/agents/components/duplicate-agent-button.tsx +42 -0
  34. package/blocks/agents/components/from-template-button.tsx +65 -0
  35. package/blocks/agents/components/knowledge-browser.tsx +107 -0
  36. package/blocks/agents/components/knowledge-detail.tsx +156 -0
  37. package/blocks/agents/components/knowledge-form.tsx +69 -0
  38. package/blocks/agents/components/name-dialog.tsx +32 -0
  39. package/blocks/agents/components/receptionist-button.tsx +46 -0
  40. package/blocks/agents/components/save-as-template-button.tsx +32 -0
  41. package/blocks/agents/components/skill-editor.tsx +147 -0
  42. package/blocks/agents/components/skill-library.tsx +111 -0
  43. package/blocks/agents/lib/agent-types.ts +7 -1
  44. package/blocks/agents/lib/facts.tsx +13 -0
  45. package/blocks/agents/lib/knowledge-utils.ts +49 -0
  46. package/blocks/agents/lib/load-more.tsx +141 -0
  47. package/blocks/agents/lib/skill-utils.ts +91 -0
  48. package/blocks/agents/recipes/create-agent-and-attach-skill.ts +1 -1
  49. package/blocks/analytics/components/analytics-screen.tsx +16 -3
  50. package/blocks/analytics/components/kpi-tiles.tsx +1 -1
  51. package/blocks/analytics/components/report-builder.tsx +15 -2
  52. package/blocks/appointments/README.md +6 -0
  53. package/blocks/appointments/block.json +27 -0
  54. package/blocks/appointments/components/booking-page.tsx +2 -2
  55. package/blocks/appointments/components/meeting-contact-links.tsx +49 -0
  56. package/blocks/appointments/components/meeting-detail.tsx +2 -2
  57. package/blocks/appointments/components/meeting-list.tsx +29 -13
  58. package/blocks/appointments/components/record-meetings-tab.tsx +92 -0
  59. package/blocks/campaigns/README.md +1 -1
  60. package/blocks/campaigns/block.json +34 -1
  61. package/blocks/campaigns/components/campaign-assets.tsx +1 -1
  62. package/blocks/campaigns/components/campaign-launch-step.tsx +16 -11
  63. package/blocks/campaigns/components/campaign-links.tsx +180 -0
  64. package/blocks/campaigns/components/campaign-metrics.tsx +1 -1
  65. package/blocks/campaigns/components/campaign-wizard.tsx +10 -5
  66. package/blocks/campaigns/components/icp-detail.tsx +11 -2
  67. package/blocks/campaigns/components/icp-editor.tsx +8 -3
  68. package/blocks/campaigns/components/persona-detail.tsx +11 -2
  69. package/blocks/campaigns/components/persona-editor.tsx +6 -1
  70. package/blocks/campaigns/lib/campaigns-utils.ts +4 -4
  71. package/blocks/coach/components/call-scorecard.tsx +7 -7
  72. package/blocks/company-intelligence/README.md +132 -0
  73. package/blocks/company-intelligence/block.json +318 -0
  74. package/blocks/company-intelligence/components/company-intelligence-screen.tsx +114 -0
  75. package/blocks/company-intelligence/components/company-intelligence-tab.tsx +88 -0
  76. package/blocks/company-intelligence/components/company-profile.tsx +68 -0
  77. package/blocks/company-intelligence/components/intelligence-sources.tsx +63 -0
  78. package/blocks/company-intelligence/components/report-detail.tsx +189 -0
  79. package/blocks/company-intelligence/components/research-reports.tsx +136 -0
  80. package/blocks/company-intelligence/components/research-run.tsx +165 -0
  81. package/blocks/company-intelligence/components/source-detail.tsx +117 -0
  82. package/blocks/company-intelligence/components/source-view.tsx +274 -0
  83. package/blocks/company-intelligence/components/wiki-document-detail.tsx +116 -0
  84. package/blocks/company-intelligence/components/wiki-documents.tsx +66 -0
  85. package/blocks/company-intelligence/hooks/use-intelligence.ts +173 -0
  86. package/blocks/company-intelligence/lib/intelligence-types.ts +230 -0
  87. package/blocks/company-intelligence/lib/safe-markdown.tsx +150 -0
  88. package/blocks/company-intelligence/recipes/read-competitors-and-news.ts +33 -0
  89. package/blocks/company-intelligence/recipes/research-your-website.ts +43 -0
  90. package/blocks/company-intelligence/recipes/write-the-research-reports.ts +54 -0
  91. package/blocks/copilot/components/copilot-memory.tsx +6 -2
  92. package/blocks/copilot/components/copilot-panel.tsx +1 -1
  93. package/blocks/copilot/components/copilot-team-chat.tsx +6 -1
  94. package/blocks/crm/README.md +25 -0
  95. package/blocks/crm/block.json +257 -9
  96. package/blocks/crm/components/bulk-update.tsx +119 -0
  97. package/blocks/crm/components/companies-screen.tsx +23 -9
  98. package/blocks/crm/components/company-detail.tsx +2 -2
  99. package/blocks/crm/components/contact-detail.tsx +4 -4
  100. package/blocks/crm/components/contact-documents-tab.tsx +144 -0
  101. package/blocks/crm/components/contact-insights-tab.tsx +118 -0
  102. package/blocks/crm/components/contact-lookup-link.tsx +85 -0
  103. package/blocks/crm/components/contact-row-actions.tsx +43 -0
  104. package/blocks/crm/components/contact-tag-chips.tsx +113 -0
  105. package/blocks/crm/components/contacts-screen.tsx +77 -18
  106. package/blocks/crm/components/dedupe-review.tsx +6 -1
  107. package/blocks/crm/components/import-wizard.tsx +3 -7
  108. package/blocks/crm/components/list-select.tsx +20 -0
  109. package/blocks/crm/components/owner-assign.tsx +132 -0
  110. package/blocks/crm/components/record-engagement-tab.tsx +103 -0
  111. package/blocks/crm/components/record-form.tsx +1 -1
  112. package/blocks/crm/components/record-open-links.tsx +79 -0
  113. package/blocks/crm/components/tag-assign.tsx +112 -0
  114. package/blocks/crm/components/tag-manager.tsx +178 -0
  115. package/blocks/crm/components/tasks-screen.tsx +35 -15
  116. package/blocks/crm/components/unlock-info-button.tsx +82 -0
  117. package/blocks/crm/components/verify-email-button.tsx +93 -0
  118. package/blocks/crm/hooks/use-all-lists.ts +18 -0
  119. package/blocks/crm/hooks/use-contact-tags.ts +29 -0
  120. package/blocks/crm/hooks/use-page-query.ts +3 -1
  121. package/blocks/crm/lib/crm-types.ts +14 -0
  122. package/blocks/crm/lib/read-lists.ts +16 -0
  123. package/blocks/crm/lib/record-actions.ts +102 -0
  124. package/blocks/deals/README.md +25 -6
  125. package/blocks/deals/block.json +168 -2
  126. package/blocks/deals/components/close-deal-dialog.tsx +169 -0
  127. package/blocks/deals/components/create-deal-button.tsx +109 -0
  128. package/blocks/deals/components/deal-contacts-editor.tsx +134 -0
  129. package/blocks/deals/components/deal-detail.tsx +7 -5
  130. package/blocks/deals/components/deal-filters.tsx +65 -0
  131. package/blocks/deals/components/deal-line-items.tsx +120 -0
  132. package/blocks/deals/components/deal-notes-tab.tsx +97 -0
  133. package/blocks/deals/components/deal-related.tsx +30 -9
  134. package/blocks/deals/components/deal-tasks-tab.tsx +88 -0
  135. package/blocks/deals/components/deals-screen.tsx +57 -22
  136. package/blocks/deals/components/forecast-view.tsx +4 -4
  137. package/blocks/deals/components/pipeline-board.tsx +8 -6
  138. package/blocks/deals/components/pipeline-editor.tsx +132 -0
  139. package/blocks/deals/components/record-deals-tab.tsx +62 -0
  140. package/blocks/deals/components/stage-editor.tsx +1 -1
  141. package/blocks/deals/hooks/use-pipeline-deals.ts +17 -4
  142. package/blocks/deals/lib/deal-extras.ts +156 -0
  143. package/blocks/dialer/README.md +14 -5
  144. package/blocks/dialer/block.json +17 -2
  145. package/blocks/dialer/components/call-contact-button.tsx +26 -9
  146. package/blocks/dialer/components/call-log-screen.tsx +10 -2
  147. package/blocks/dialer/components/call-log.tsx +16 -4
  148. package/blocks/dialer/components/call-queue.tsx +3 -3
  149. package/blocks/dialer/components/dialer-screen.tsx +69 -27
  150. package/blocks/dialer/components/disposition-panel.tsx +1 -1
  151. package/blocks/dialer/components/record-calls-tab.tsx +101 -0
  152. package/blocks/dialer/components/session-start-form.tsx +58 -11
  153. package/blocks/dialer/components/softphone.tsx +1 -1
  154. package/blocks/documents/README.md +86 -0
  155. package/blocks/documents/block.json +378 -0
  156. package/blocks/documents/components/account-bar.tsx +48 -0
  157. package/blocks/documents/components/correspondence-form.tsx +95 -0
  158. package/blocks/documents/components/correspondence-import.tsx +106 -0
  159. package/blocks/documents/components/correspondence-panel.tsx +191 -0
  160. package/blocks/documents/components/documents-screen.tsx +76 -0
  161. package/blocks/documents/components/library-document-detail.tsx +175 -0
  162. package/blocks/documents/components/library-document-form.tsx +105 -0
  163. package/blocks/documents/components/library-folder-form.tsx +74 -0
  164. package/blocks/documents/components/library-panel.tsx +235 -0
  165. package/blocks/documents/components/library-upload.tsx +160 -0
  166. package/blocks/documents/components/question-row.tsx +130 -0
  167. package/blocks/documents/components/questionnaire-detail.tsx +197 -0
  168. package/blocks/documents/components/questionnaires-panel.tsx +173 -0
  169. package/blocks/documents/components/record-documents-tab.tsx +109 -0
  170. package/blocks/documents/lib/documents-types.ts +252 -0
  171. package/blocks/documents/lib/download.ts +64 -0
  172. package/blocks/documents/recipes/follow-a-questionnaire.ts +26 -0
  173. package/blocks/documents/recipes/log-account-correspondence.ts +27 -0
  174. package/blocks/documents/recipes/organize-the-library.ts +25 -0
  175. package/blocks/email-signatures/README.md +123 -0
  176. package/blocks/email-signatures/block.json +341 -0
  177. package/blocks/email-signatures/components/email-signatures-screen.tsx +166 -0
  178. package/blocks/email-signatures/components/signature-assign-template.tsx +119 -0
  179. package/blocks/email-signatures/components/signature-block-editor.tsx +87 -0
  180. package/blocks/email-signatures/components/signature-campaign-form.tsx +165 -0
  181. package/blocks/email-signatures/components/signature-campaigns.tsx +75 -0
  182. package/blocks/email-signatures/components/signature-identity-form.tsx +131 -0
  183. package/blocks/email-signatures/components/signature-mailboxes.tsx +195 -0
  184. package/blocks/email-signatures/components/signature-policy.tsx +130 -0
  185. package/blocks/email-signatures/components/signature-preview.tsx +119 -0
  186. package/blocks/email-signatures/components/signature-report.tsx +77 -0
  187. package/blocks/email-signatures/components/signature-template-details.tsx +112 -0
  188. package/blocks/email-signatures/components/signature-template-form.tsx +109 -0
  189. package/blocks/email-signatures/hooks/use-signatures-data.ts +93 -0
  190. package/blocks/email-signatures/lib/signatures-types.ts +392 -0
  191. package/blocks/email-signatures/recipes/assign-a-signature-to-a-new-hire.ts +32 -0
  192. package/blocks/email-signatures/recipes/create-a-template-and-make-it-default.ts +35 -0
  193. package/blocks/email-signatures/recipes/signature-engagement-report.ts +16 -0
  194. package/blocks/enrichment/README.md +38 -10
  195. package/blocks/enrichment/block.json +164 -12
  196. package/blocks/enrichment/components/auto-enrichment-configs.tsx +134 -0
  197. package/blocks/enrichment/components/auto-enrichment-settings.tsx +82 -0
  198. package/blocks/enrichment/components/bulk-enrich-panel.tsx +79 -30
  199. package/blocks/enrichment/components/email-verify-badge.tsx +3 -3
  200. package/blocks/enrichment/components/enrich-button.tsx +1 -1
  201. package/blocks/enrichment/components/enrichment-activity.tsx +93 -0
  202. package/blocks/enrichment/components/enrichment-job-detail.tsx +18 -0
  203. package/blocks/enrichment/components/enrichment-screen.tsx +103 -19
  204. package/blocks/enrichment/components/list-pipelines.tsx +97 -0
  205. package/blocks/enrichment/components/pipeline-detail.tsx +214 -0
  206. package/blocks/enrichment/components/pipeline-editor.tsx +144 -0
  207. package/blocks/enrichment/components/pipeline-templates.tsx +90 -0
  208. package/blocks/enrichment/components/waterfall-config.tsx +27 -7
  209. package/blocks/enrichment/lib/enrichment-types.ts +51 -0
  210. package/blocks/enrichment/lib/pipeline-types.ts +234 -0
  211. package/blocks/enrichment/recipes/bulk-enrich-and-poll.ts +15 -4
  212. package/blocks/forms/README.md +10 -0
  213. package/blocks/forms/block.json +107 -0
  214. package/blocks/forms/components/form-activity.tsx +71 -0
  215. package/blocks/forms/components/form-backfill.tsx +108 -0
  216. package/blocks/forms/components/form-builder.tsx +1 -1
  217. package/blocks/forms/components/form-embed.tsx +1 -1
  218. package/blocks/forms/components/form-groups.tsx +151 -0
  219. package/blocks/forms/components/form-mapping-editor.tsx +6 -9
  220. package/blocks/forms/components/form-route-history.tsx +72 -0
  221. package/blocks/forms/components/form-saved-views.tsx +81 -0
  222. package/blocks/forms/components/forms-screen.tsx +57 -20
  223. package/blocks/forms/components/more-rows.tsx +30 -0
  224. package/blocks/forms/components/submissions-export.tsx +67 -0
  225. package/blocks/forms/components/submissions-table.tsx +15 -6
  226. package/blocks/forms/lib/forms-extra.ts +67 -0
  227. package/blocks/inbox/README.md +45 -4
  228. package/blocks/inbox/block.json +145 -8
  229. package/blocks/inbox/components/blocked-senders.tsx +103 -0
  230. package/blocks/inbox/components/compose-message.tsx +193 -0
  231. package/blocks/inbox/components/inbox-screen.tsx +54 -6
  232. package/blocks/inbox/components/inbox-search.tsx +106 -0
  233. package/blocks/inbox/components/record-conversations-tab.tsx +154 -0
  234. package/blocks/inbox/components/tag-manager.tsx +136 -0
  235. package/blocks/inbox/components/thread-actions.tsx +133 -0
  236. package/blocks/inbox/components/thread-badge.tsx +2 -2
  237. package/blocks/inbox/components/thread-view.tsx +3 -1
  238. package/blocks/inbox/hooks/use-inbox-mailboxes.ts +31 -0
  239. package/blocks/inbox/lib/inbox-manage.ts +227 -0
  240. package/blocks/integrations/README.md +54 -1
  241. package/blocks/integrations/block.json +189 -15
  242. package/blocks/integrations/components/ad-accounts.tsx +82 -0
  243. package/blocks/integrations/components/connection-health.tsx +59 -0
  244. package/blocks/integrations/components/crm-detail.tsx +20 -1
  245. package/blocks/integrations/components/crm-records.tsx +103 -0
  246. package/blocks/integrations/components/field-mappings.tsx +61 -0
  247. package/blocks/integrations/components/integration-list.tsx +4 -4
  248. package/blocks/integrations/components/integrations-screen.tsx +20 -3
  249. package/blocks/integrations/components/migration-panel.tsx +133 -0
  250. package/blocks/integrations/components/sugarcrm-connect.tsx +95 -0
  251. package/blocks/integrations/components/sync-status.tsx +6 -6
  252. package/blocks/integrations/components/sync-triggers.tsx +134 -0
  253. package/blocks/integrations/components/webhook-detail.tsx +26 -7
  254. package/blocks/integrations/components/webhook-manager.tsx +30 -17
  255. package/blocks/integrations/components/workspace-tools.tsx +127 -0
  256. package/blocks/integrations/lib/crm-utils.ts +39 -0
  257. package/blocks/integrations/lib/facts.tsx +13 -0
  258. package/blocks/integrations/lib/integrations-utils.ts +5 -0
  259. package/blocks/integrations/lib/load-more.tsx +141 -0
  260. package/blocks/intent/components/account-intent-score.tsx +5 -5
  261. package/blocks/intent/components/intent-feed.tsx +8 -8
  262. package/blocks/intent/components/intent-keyword-manager.tsx +8 -8
  263. package/blocks/intent/lib/intent-utils.ts +4 -4
  264. package/blocks/lifecycle/components/account-related.tsx +8 -1
  265. package/blocks/lifecycle/components/churn-list.tsx +5 -2
  266. package/blocks/lifecycle/components/customer-table.tsx +1 -1
  267. package/blocks/lists/README.md +7 -1
  268. package/blocks/lists/block.json +31 -3
  269. package/blocks/lists/components/add-company-people-to-list-button.tsx +73 -0
  270. package/blocks/lists/components/add-to-list-button.tsx +17 -7
  271. package/blocks/lists/components/list-picker.tsx +13 -3
  272. package/blocks/lists/components/list-table.tsx +1 -1
  273. package/blocks/lists/components/lists-screen.tsx +4 -2
  274. package/blocks/lists/components/record-lists-tab.tsx +99 -0
  275. package/blocks/lists/components/suppression-manager.tsx +27 -6
  276. package/blocks/lists/components/suppressions-screen.tsx +21 -12
  277. package/blocks/mailboxes/block.json +4 -0
  278. package/blocks/mailboxes/components/connect-mailbox.tsx +9 -8
  279. package/blocks/mailboxes/components/domain-detail.tsx +10 -4
  280. package/blocks/mailboxes/components/domain-purchase.tsx +14 -11
  281. package/blocks/mailboxes/components/mailbox-detail.tsx +3 -2
  282. package/blocks/mailboxes/components/mailbox-list.tsx +8 -3
  283. package/blocks/mailboxes/components/mailboxes-screen.tsx +8 -3
  284. package/blocks/mailboxes/components/warmup-health.tsx +20 -20
  285. package/blocks/mailboxes/lib/mailboxes-utils.ts +4 -4
  286. package/blocks/mailboxes/lib/use-provider-domains.ts +23 -0
  287. package/blocks/newsletter/README.md +12 -0
  288. package/blocks/newsletter/block.json +117 -0
  289. package/blocks/newsletter/components/issue-scheduler.tsx +2 -2
  290. package/blocks/newsletter/components/issue-versions.tsx +93 -0
  291. package/blocks/newsletter/components/more-rows.tsx +30 -0
  292. package/blocks/newsletter/components/newsletter-editor.tsx +1 -1
  293. package/blocks/newsletter/components/newsletter-list-syncs.tsx +121 -0
  294. package/blocks/newsletter/components/newsletter-screen.tsx +38 -13
  295. package/blocks/newsletter/components/newsletter-settings.tsx +211 -0
  296. package/blocks/newsletter/components/newsletter-stats.tsx +2 -2
  297. package/blocks/newsletter/components/newsletter-templates.tsx +133 -0
  298. package/blocks/newsletter/components/subscriber-table.tsx +5 -7
  299. package/blocks/newsletter/components/subscriber-timeline.tsx +65 -0
  300. package/blocks/newsletter/lib/newsletter-extra.ts +60 -0
  301. package/blocks/nurture/components/nurture-builder.tsx +10 -2
  302. package/blocks/nurture/components/nurture-enroll.tsx +6 -7
  303. package/blocks/nurture/components/nurture-form.tsx +5 -8
  304. package/blocks/nurture/components/nurture-screen.tsx +16 -5
  305. package/blocks/nurture/components/nurture-stats.tsx +5 -4
  306. package/blocks/objects/README.md +1 -1
  307. package/blocks/objects/block.json +13 -5
  308. package/blocks/objects/components/attribute-field-input.tsx +14 -1
  309. package/blocks/objects/components/object-record-detail.tsx +8 -1
  310. package/blocks/objects/components/object-schema-editor.tsx +1 -1
  311. package/blocks/objects/components/record-roles-panel.tsx +15 -5
  312. package/blocks/pages/README.md +14 -0
  313. package/blocks/pages/block.json +123 -2
  314. package/blocks/pages/components/more-rows.tsx +30 -0
  315. package/blocks/pages/components/page-ai-tools.tsx +196 -0
  316. package/blocks/pages/components/page-analytics.tsx +176 -0
  317. package/blocks/pages/components/page-clone.tsx +99 -0
  318. package/blocks/pages/components/page-domains.tsx +167 -0
  319. package/blocks/pages/components/page-editor.tsx +1 -1
  320. package/blocks/pages/components/page-generation-status.tsx +48 -0
  321. package/blocks/pages/components/page-tracking.tsx +137 -0
  322. package/blocks/pages/components/pages-screen.tsx +57 -16
  323. package/blocks/pages/components/seo-report.tsx +6 -1
  324. package/blocks/pages/hooks/use-landing-page-paths.ts +60 -0
  325. package/blocks/pages/lib/studio.ts +7 -0
  326. package/blocks/phone-numbers/README.md +74 -0
  327. package/blocks/phone-numbers/block.json +262 -0
  328. package/blocks/phone-numbers/components/a2p-registration.tsx +230 -0
  329. package/blocks/phone-numbers/components/assign-number.tsx +104 -0
  330. package/blocks/phone-numbers/components/number-search.tsx +239 -0
  331. package/blocks/phone-numbers/components/number-settings.tsx +134 -0
  332. package/blocks/phone-numbers/components/number-usage.tsx +97 -0
  333. package/blocks/phone-numbers/components/phone-number-detail.tsx +84 -0
  334. package/blocks/phone-numbers/components/phone-number-list.tsx +110 -0
  335. package/blocks/phone-numbers/components/phone-numbers-screen.tsx +201 -0
  336. package/blocks/phone-numbers/components/register-owned-number.tsx +98 -0
  337. package/blocks/phone-numbers/components/release-number.tsx +126 -0
  338. package/blocks/phone-numbers/hooks/use-phone-numbers.ts +58 -0
  339. package/blocks/phone-numbers/lib/phone-numbers-utils.ts +202 -0
  340. package/blocks/phone-numbers/recipes/01-search-and-buy-number.ts +49 -0
  341. package/blocks/phone-numbers/recipes/02-assign-number-to-rep.ts +25 -0
  342. package/blocks/phone-numbers/recipes/03-audit-numbers.ts +36 -0
  343. package/blocks/phone-numbers/recipes/04-register-text-messaging.ts +39 -0
  344. package/blocks/pickers/README.md +23 -0
  345. package/blocks/pickers/block.json +103 -0
  346. package/blocks/pickers/components/company-picker.tsx +90 -0
  347. package/blocks/pickers/components/contact-picker.tsx +131 -0
  348. package/blocks/pickers/components/member-picker.tsx +99 -0
  349. package/blocks/pickers/components/search-picker.tsx +98 -0
  350. package/blocks/pickers/hooks/use-current-member.ts +104 -0
  351. package/blocks/pickers/hooks/use-picker-pages.ts +73 -0
  352. package/blocks/pickers/lib/use-debounced.ts +13 -0
  353. package/blocks/programmatic-pages/README.md +82 -0
  354. package/blocks/programmatic-pages/block.json +292 -0
  355. package/blocks/programmatic-pages/components/programmatic-campaign-form.tsx +136 -0
  356. package/blocks/programmatic-pages/components/programmatic-generate.tsx +112 -0
  357. package/blocks/programmatic-pages/components/programmatic-generated-pages.tsx +210 -0
  358. package/blocks/programmatic-pages/components/programmatic-overview.tsx +84 -0
  359. package/blocks/programmatic-pages/components/programmatic-pages-screen.tsx +221 -0
  360. package/blocks/programmatic-pages/components/programmatic-preview.tsx +66 -0
  361. package/blocks/programmatic-pages/components/programmatic-publish.tsx +102 -0
  362. package/blocks/programmatic-pages/components/programmatic-settings.tsx +96 -0
  363. package/blocks/programmatic-pages/components/programmatic-source-fields.tsx +75 -0
  364. package/blocks/programmatic-pages/components/programmatic-source.tsx +106 -0
  365. package/blocks/programmatic-pages/components/programmatic-variables.tsx +84 -0
  366. package/blocks/programmatic-pages/hooks/use-programmatic-workspace.ts +19 -0
  367. package/blocks/programmatic-pages/lib/programmatic-types.ts +330 -0
  368. package/blocks/programmatic-pages/recipes/create-a-programmatic-campaign.ts +23 -0
  369. package/blocks/programmatic-pages/recipes/render-and-follow.ts +21 -0
  370. package/blocks/programmatic-pages/recipes/review-then-publish.ts +17 -0
  371. package/blocks/quotes/README.md +38 -1
  372. package/blocks/quotes/block.json +170 -6
  373. package/blocks/quotes/components/create-quote-from-deal.tsx +48 -0
  374. package/blocks/quotes/components/manual-products.tsx +144 -0
  375. package/blocks/quotes/components/quote-batch-actions.tsx +86 -0
  376. package/blocks/quotes/components/quote-builder.tsx +1 -1
  377. package/blocks/quotes/components/quote-documents.tsx +94 -0
  378. package/blocks/quotes/components/quote-evidence.tsx +95 -0
  379. package/blocks/quotes/components/quote-lifecycle-actions.tsx +146 -0
  380. package/blocks/quotes/components/quote-list.tsx +28 -8
  381. package/blocks/quotes/components/quote-related.tsx +3 -2
  382. package/blocks/quotes/components/quote-settings.tsx +184 -0
  383. package/blocks/quotes/components/quote-templates.tsx +189 -0
  384. package/blocks/quotes/components/quote-viewer.tsx +23 -5
  385. package/blocks/quotes/components/quotes-screen.tsx +15 -5
  386. package/blocks/quotes/components/record-quotes-tab.tsx +90 -0
  387. package/blocks/quotes/lib/quote-admin.ts +264 -0
  388. package/blocks/radar/components/competitor-battle-card.tsx +1 -1
  389. package/blocks/radar/components/radar-overview.tsx +4 -4
  390. package/blocks/radar/components/radar-screen.tsx +2 -2
  391. package/blocks/sequencer/README.md +61 -0
  392. package/blocks/sequencer/block.json +200 -6
  393. package/blocks/sequencer/components/add-to-sequence-button.tsx +82 -0
  394. package/blocks/sequencer/components/enroll-dialog.tsx +2 -2
  395. package/blocks/sequencer/components/enrollment-withdraw.tsx +71 -0
  396. package/blocks/sequencer/components/record-sequences-tab.tsx +126 -0
  397. package/blocks/sequencer/components/sequence-builder.tsx +32 -23
  398. package/blocks/sequencer/components/sequence-campaign-link.tsx +78 -0
  399. package/blocks/sequencer/components/sequence-detail.tsx +10 -2
  400. package/blocks/sequencer/components/sequence-edit-form.tsx +111 -0
  401. package/blocks/sequencer/components/sequence-enrollments.tsx +5 -2
  402. package/blocks/sequencer/components/sequence-list.tsx +1 -1
  403. package/blocks/sequencer/components/sequence-manage-actions.tsx +119 -0
  404. package/blocks/sequencer/components/sequence-senders-panel.tsx +84 -0
  405. package/blocks/sequencer/components/sequence-stats.tsx +8 -8
  406. package/blocks/sequencer/components/sequence-templates.tsx +160 -0
  407. package/blocks/sequencer/components/sequences-screen.tsx +39 -6
  408. package/blocks/sequencer/components/step-ai-assist.tsx +196 -0
  409. package/blocks/sequencer/components/step-editor.tsx +21 -12
  410. package/blocks/sequencer/components/step-templates.tsx +224 -0
  411. package/blocks/sequencer/lib/sequencer-manage.ts +235 -0
  412. package/blocks/sequencer/lib/sequencer-utils.ts +9 -5
  413. package/blocks/signals/README.md +39 -0
  414. package/blocks/signals/block.json +287 -0
  415. package/blocks/signals/components/auto-seed-panel.tsx +111 -0
  416. package/blocks/signals/components/listener-form.tsx +184 -0
  417. package/blocks/signals/components/matched-posts.tsx +195 -0
  418. package/blocks/signals/components/post-engagements.tsx +114 -0
  419. package/blocks/signals/components/record-social-tab.tsx +49 -0
  420. package/blocks/signals/components/social-listeners-screen.tsx +250 -0
  421. package/blocks/signals/components/social-settings.tsx +128 -0
  422. package/blocks/signals/components/source-lists.tsx +83 -0
  423. package/blocks/signals/components/top-engagers.tsx +68 -0
  424. package/blocks/signals/components/x-integration.tsx +129 -0
  425. package/blocks/signals/lib/signals-types.ts +228 -0
  426. package/blocks/signals/recipes/preview-and-create-a-listener.ts +16 -0
  427. package/blocks/signals/recipes/spend-against-caps.ts +14 -0
  428. package/blocks/signals/recipes/triage-matched-posts.ts +18 -0
  429. package/blocks/social-ads/README.md +8 -0
  430. package/blocks/social-ads/block.json +137 -4
  431. package/blocks/social-ads/components/audience-sync-detail.tsx +9 -3
  432. package/blocks/social-ads/components/audience-sync.tsx +6 -2
  433. package/blocks/social-ads/components/campaign-ads.tsx +166 -0
  434. package/blocks/social-ads/components/campaign-detail.tsx +6 -1
  435. package/blocks/social-ads/components/campaign-editor.tsx +134 -0
  436. package/blocks/social-ads/components/creative-concepts.tsx +74 -0
  437. package/blocks/social-ads/components/creative-detail.tsx +6 -1
  438. package/blocks/social-ads/components/creative-gallery.tsx +20 -2
  439. package/blocks/social-ads/components/creative-revisions.tsx +57 -0
  440. package/blocks/social-ads/components/creative-tools.tsx +176 -0
  441. package/blocks/social-ads/components/post-composer.tsx +4 -2
  442. package/blocks/social-ads/components/post-detail.tsx +3 -0
  443. package/blocks/social-ads/components/social-ideas.tsx +64 -0
  444. package/blocks/social-ads/components/social-performance.tsx +80 -0
  445. package/blocks/social-ads/components/social-screen.tsx +33 -6
  446. package/blocks/social-ads/lib/ads-extra.ts +67 -0
  447. package/blocks/surveys/README.md +91 -0
  448. package/blocks/surveys/block.json +299 -0
  449. package/blocks/surveys/components/account-nps.tsx +69 -0
  450. package/blocks/surveys/components/contact-survey-history.tsx +52 -0
  451. package/blocks/surveys/components/org-summary.tsx +82 -0
  452. package/blocks/surveys/components/sending-domains.tsx +113 -0
  453. package/blocks/surveys/components/survey-form.tsx +126 -0
  454. package/blocks/surveys/components/survey-responses.tsx +145 -0
  455. package/blocks/surveys/components/survey-results.tsx +72 -0
  456. package/blocks/surveys/components/survey-send-history.tsx +58 -0
  457. package/blocks/surveys/components/survey-send.tsx +162 -0
  458. package/blocks/surveys/components/survey-triggers.tsx +166 -0
  459. package/blocks/surveys/components/surveys-screen.tsx +234 -0
  460. package/blocks/surveys/lib/surveys-types.ts +228 -0
  461. package/blocks/surveys/recipes/create-an-nps-survey.ts +22 -0
  462. package/blocks/surveys/recipes/send-a-survey-and-follow-it.ts +27 -0
  463. package/blocks/surveys/recipes/survey-score-report.ts +27 -0
  464. package/blocks/visitors/components/snippet-install.tsx +18 -9
  465. package/blocks/visitors/components/traffic-chart.tsx +7 -6
  466. package/blocks/visitors/components/visitor-company-card.tsx +24 -14
  467. package/blocks/visitors/components/visitor-feed.tsx +5 -5
  468. package/blocks/web-analytics/README.md +102 -0
  469. package/blocks/web-analytics/block.json +292 -0
  470. package/blocks/web-analytics/components/acquisition-tab.tsx +154 -0
  471. package/blocks/web-analytics/components/analytics-filters.tsx +161 -0
  472. package/blocks/web-analytics/components/audience-tab.tsx +135 -0
  473. package/blocks/web-analytics/components/conversions-tab.tsx +128 -0
  474. package/blocks/web-analytics/components/engagement-tab.tsx +123 -0
  475. package/blocks/web-analytics/components/overview-tab.tsx +102 -0
  476. package/blocks/web-analytics/components/pages-tab.tsx +148 -0
  477. package/blocks/web-analytics/components/ranked-table.tsx +103 -0
  478. package/blocks/web-analytics/components/realtime-tab.tsx +103 -0
  479. package/blocks/web-analytics/components/report-card.tsx +71 -0
  480. package/blocks/web-analytics/components/web-analytics-screen.tsx +90 -0
  481. package/blocks/web-analytics/hooks/use-report.ts +48 -0
  482. package/blocks/web-analytics/lib/analytics-scope.ts +155 -0
  483. package/blocks/web-analytics/lib/page-path.ts +14 -0
  484. package/blocks/web-analytics/lib/web-analytics-types.ts +187 -0
  485. package/blocks/web-analytics/recipes/best-landing-pages.ts +26 -0
  486. package/blocks/web-analytics/recipes/form-conversion-check.ts +19 -0
  487. package/blocks/web-analytics/recipes/weekly-traffic-report.ts +37 -0
  488. package/blocks/webchat/components/chat-widget-config.tsx +1 -1
  489. package/blocks/webchat/components/conversation-list.tsx +1 -1
  490. package/blocks/workbench/README.md +54 -2
  491. package/blocks/workbench/block.json +234 -5
  492. package/blocks/workbench/components/column-recipe-editor.tsx +1 -1
  493. package/blocks/workbench/components/run-progress.tsx +1 -1
  494. package/blocks/workbench/components/workbench-auto-enrich.tsx +88 -0
  495. package/blocks/workbench/components/workbench-automation.tsx +36 -0
  496. package/blocks/workbench/components/workbench-connections.tsx +136 -0
  497. package/blocks/workbench/components/workbench-crm-import.tsx +91 -0
  498. package/blocks/workbench/components/workbench-datafile-import.tsx +154 -0
  499. package/blocks/workbench/components/workbench-grid.tsx +71 -8
  500. package/blocks/workbench/components/workbench-pipelines.tsx +173 -0
  501. package/blocks/workbench/components/workbench-row-actions.tsx +8 -1
  502. package/blocks/workbench/components/workbench-schedule.tsx +191 -0
  503. package/blocks/workbench/components/workbench-screen.tsx +65 -22
  504. package/blocks/workbench/components/workbench-send-to-sequence.tsx +116 -0
  505. package/blocks/workbench/components/workbench-table-list.tsx +14 -2
  506. package/blocks/workbench/components/workbench-table-settings.tsx +53 -0
  507. package/blocks/workbench/components/workbench-triggers.tsx +178 -0
  508. package/blocks/workbench/hooks/use-connected-crms.ts +29 -0
  509. package/blocks/workbench/lib/api-status.ts +8 -0
  510. package/blocks/workbench/lib/automation-types.ts +257 -0
  511. package/blocks/workflows/components/workflow-editor.tsx +1 -1
  512. package/dist/cli.js +744 -394
  513. package/dist/index.browser.js +1 -1
  514. package/dist/index.browser.js.map +1 -1
  515. package/dist/index.browser.mjs +1 -1
  516. package/dist/index.browser.mjs.map +1 -1
  517. package/dist/index.d.mts +2 -2
  518. package/dist/index.d.ts +2 -2
  519. package/dist/index.js +1 -1
  520. package/dist/index.js.map +1 -1
  521. package/dist/index.mjs +1 -1
  522. package/dist/index.mjs.map +1 -1
  523. package/dist/react.browser.js +1 -1
  524. package/dist/react.browser.js.map +1 -1
  525. package/dist/react.browser.mjs +1 -1
  526. package/dist/react.browser.mjs.map +1 -1
  527. package/dist/react.d.mts +2 -2
  528. package/dist/react.d.ts +2 -2
  529. package/dist/react.js +1 -1
  530. package/dist/react.js.map +1 -1
  531. package/dist/react.mjs +1 -1
  532. package/dist/react.mjs.map +1 -1
  533. package/dist/types/blocks/auth.d.ts +45 -0
  534. package/dist/types/blocks/brand.d.ts +11 -2
  535. package/dist/types/blocks/create.d.ts +11 -4
  536. package/dist/types/blocks/doctor.d.ts +1 -0
  537. package/dist/types/blocks/flows.d.ts +7 -1
  538. package/dist/types/blocks/orgBrand.d.ts +34 -0
  539. package/dist/types/cli.d.ts +3 -0
  540. package/dist/types/version.d.ts +2 -2
  541. package/docs/api/desk.d.ts +2 -2
  542. package/docs/api/desk.md +3 -3
  543. package/docs/api/forms.md +1 -1
  544. package/package.json +1 -1
  545. package/stacks/6sense/pages/companies.tsx.tmpl +21 -0
  546. package/stacks/6sense/pages/contacts.tsx.tmpl +21 -0
  547. package/stacks/6sense/pages/tasks.tsx.tmpl +19 -0
  548. package/stacks/6sense.json +37 -4
  549. package/stacks/apollo/pages/calls.tsx.tmpl +23 -0
  550. package/stacks/apollo/pages/campaigns.tsx.tmpl +27 -0
  551. package/stacks/apollo/pages/companies.tsx.tmpl +19 -36
  552. package/stacks/apollo/pages/contacts.tsx.tmpl +35 -95
  553. package/stacks/apollo/pages/deals.tsx.tmpl +17 -0
  554. package/stacks/apollo/pages/inbox-contact.tsx.tmpl +13 -0
  555. package/stacks/apollo/pages/lists.tsx.tmpl +24 -0
  556. package/stacks/apollo/pages/meetings.tsx.tmpl +13 -0
  557. package/stacks/apollo/pages/sequences.tsx.tmpl +18 -0
  558. package/stacks/apollo/pages/tasks.tsx.tmpl +20 -0
  559. package/stacks/apollo.json +68 -9
  560. package/stacks/calendly/pages/companies.tsx.tmpl +19 -0
  561. package/stacks/calendly/pages/contacts.tsx.tmpl +21 -0
  562. package/stacks/calendly/pages/meetings.tsx.tmpl +13 -0
  563. package/stacks/calendly/pages/tasks.tsx.tmpl +19 -0
  564. package/stacks/calendly.json +8 -4
  565. package/stacks/clay/pages/companies.tsx.tmpl +17 -1
  566. package/stacks/clay/pages/contacts.tsx.tmpl +14 -0
  567. package/stacks/clay/pages/lists.tsx.tmpl +24 -0
  568. package/stacks/clay/pages/tasks.tsx.tmpl +19 -0
  569. package/stacks/clay.json +16 -3
  570. package/stacks/gong/pages/calls.tsx.tmpl +23 -0
  571. package/stacks/gong/pages/companies.tsx.tmpl +22 -0
  572. package/stacks/gong/pages/contacts.tsx.tmpl +34 -0
  573. package/stacks/gong/pages/lists.tsx.tmpl +12 -0
  574. package/stacks/gong/pages/meetings.tsx.tmpl +13 -0
  575. package/stacks/gong/pages/tasks.tsx.tmpl +19 -0
  576. package/stacks/gong.json +23 -6
  577. package/stacks/hootsuite/pages/companies.tsx.tmpl +22 -0
  578. package/stacks/hootsuite/pages/contacts.tsx.tmpl +30 -0
  579. package/stacks/hootsuite/pages/lists.tsx.tmpl +12 -0
  580. package/stacks/hootsuite/pages/tasks.tsx.tmpl +19 -0
  581. package/stacks/hootsuite.json +19 -4
  582. package/stacks/hubspot/pages/campaigns.tsx.tmpl +30 -0
  583. package/stacks/hubspot/pages/companies.tsx.tmpl +16 -35
  584. package/stacks/hubspot/pages/contacts.tsx.tmpl +35 -95
  585. package/stacks/hubspot/pages/deals.tsx.tmpl +14 -1
  586. package/stacks/hubspot/pages/forms.tsx.tmpl +36 -0
  587. package/stacks/hubspot/pages/inbox.tsx.tmpl +12 -1
  588. package/stacks/hubspot/pages/lifecycle.tsx.tmpl +23 -0
  589. package/stacks/hubspot/pages/lists.tsx.tmpl +12 -0
  590. package/stacks/hubspot/pages/meetings.tsx.tmpl +13 -0
  591. package/stacks/hubspot/pages/sequences.tsx.tmpl +18 -0
  592. package/stacks/hubspot/pages/tasks.tsx.tmpl +20 -0
  593. package/stacks/hubspot/pages/web-analytics.tsx.tmpl +14 -0
  594. package/stacks/hubspot.json +66 -7
  595. package/stacks/intercom/pages/companies.tsx.tmpl +19 -0
  596. package/stacks/intercom/pages/contacts.tsx.tmpl +21 -0
  597. package/stacks/intercom/pages/inbox-contact.tsx.tmpl +13 -0
  598. package/stacks/intercom/pages/tasks.tsx.tmpl +19 -0
  599. package/stacks/intercom.json +18 -4
  600. package/stacks/mailchimp/pages/companies.tsx.tmpl +22 -0
  601. package/stacks/mailchimp/pages/contacts.tsx.tmpl +30 -0
  602. package/stacks/mailchimp/pages/forms.tsx.tmpl +36 -0
  603. package/stacks/mailchimp/pages/lists.tsx.tmpl +12 -0
  604. package/stacks/mailchimp/pages/tasks.tsx.tmpl +19 -0
  605. package/stacks/mailchimp.json +22 -6
  606. package/stacks/outreach/pages/calls.tsx.tmpl +23 -0
  607. package/stacks/outreach/pages/campaigns.tsx.tmpl +27 -0
  608. package/stacks/outreach/pages/companies.tsx.tmpl +22 -0
  609. package/stacks/outreach/pages/contacts.tsx.tmpl +29 -66
  610. package/stacks/outreach/pages/inbox-contact.tsx.tmpl +13 -0
  611. package/stacks/outreach/pages/lists.tsx.tmpl +12 -0
  612. package/stacks/outreach/pages/meetings.tsx.tmpl +13 -0
  613. package/stacks/outreach/pages/sequences.tsx.tmpl +18 -0
  614. package/stacks/outreach/pages/tasks.tsx.tmpl +19 -0
  615. package/stacks/outreach.json +38 -9
  616. package/stacks/pipedrive/pages/companies.tsx.tmpl +11 -35
  617. package/stacks/pipedrive/pages/contacts.tsx.tmpl +17 -35
  618. package/stacks/pipedrive/pages/deals.tsx.tmpl +10 -1
  619. package/stacks/pipedrive/pages/inbox.tsx.tmpl +12 -1
  620. package/stacks/pipedrive/pages/meetings.tsx.tmpl +13 -0
  621. package/stacks/pipedrive/pages/tasks.tsx.tmpl +20 -0
  622. package/stacks/pipedrive.json +14 -2
  623. package/stacks/salesforce/pages/companies.tsx.tmpl +16 -35
  624. package/stacks/salesforce/pages/contacts.tsx.tmpl +26 -35
  625. package/stacks/salesforce/pages/deals.tsx.tmpl +14 -1
  626. package/stacks/salesforce/pages/lifecycle.tsx.tmpl +23 -0
  627. package/stacks/salesforce/pages/lists.tsx.tmpl +12 -0
  628. package/stacks/salesforce/pages/tasks.tsx.tmpl +20 -0
  629. package/stacks/salesforce.json +17 -3
  630. package/stacks/zoominfo/pages/companies.tsx.tmpl +17 -1
  631. package/stacks/zoominfo/pages/contacts.tsx.tmpl +16 -0
  632. package/stacks/zoominfo/pages/lists.tsx.tmpl +24 -0
  633. package/stacks/zoominfo/pages/tasks.tsx.tmpl +19 -0
  634. package/stacks/zoominfo.json +36 -3
  635. package/styles/styles.css +1 -1
  636. package/templates/auth/auth-route.ts.tmpl +16 -0
  637. package/templates/auth/g8.auth.anonymous.ts.tmpl +15 -0
  638. package/templates/auth/g8.auth.basic.ts.tmpl +17 -0
  639. package/templates/auth/g8.auth.jwt.ts.tmpl +23 -0
  640. package/templates/auth/g8.auth.password.ts.tmpl +18 -0
  641. package/templates/auth/g8.auth.session.ts.tmpl +23 -0
  642. package/templates/auth/middleware.ts.tmpl +14 -0
  643. package/templates/next-app/README.md.tmpl +5 -0
  644. package/templates/next-app/app/globals.css.tmpl +349 -64
  645. package/templates/next-app/components/app-shell.tsx.tmpl +6 -0
  646. package/templates/next-app/components/shell/quick-jump.tsx.tmpl +4 -0
@@ -0,0 +1,341 @@
1
+ {
2
+ "$schema": "../block.schema.json",
3
+ "id": "email-signatures",
4
+ "title": "Email signatures",
5
+ "summary": "Design one signature for the team and keep every mailbox on it: templates with a live preview, assignment to mailboxes and employees, the organisation default, banner campaigns, policy and engagement.",
6
+ "features": [
7
+ "signature templates built from blocks and placeholders, with a safe live preview as a sample or as a real employee",
8
+ "apply a template to chosen mailboxes, a department or everyone, confirmed with the real number of mailboxes",
9
+ "make a template the organisation default or archive it, both confirmed",
10
+ "assign an employee to a mailbox (setup check first), push, restore the old signature and change a mailbox's source",
11
+ "banner campaigns for a time window with targeting, a preview and a who-would-see-it test",
12
+ "policy: off, managed or enforced, default and department templates, employee overrides, cold-send variant",
13
+ "impressions and clicks by mailbox and campaign, with the limits of the numbers"
14
+ ],
15
+ "dependsOn": [
16
+ "mailboxes"
17
+ ],
18
+ "operations": [
19
+ "archive_signature_template_signatures_templates__template_id__delete",
20
+ "assign_signature_identity_signatures_assignments_post",
21
+ "assign_signature_template_signatures_templates__template_id__assign_post",
22
+ "change_signature_source_signatures_mailboxes__mailbox_id__source_post",
23
+ "create_signature_campaign_signatures_campaigns_post",
24
+ "create_signature_template_signatures_templates_post",
25
+ "get_signature_report_signatures_reports_get",
26
+ "get_signature_settings_signatures_settings_get",
27
+ "get_signature_template_signatures_templates__template_id__get",
28
+ "list_mailboxes_mailboxes_get",
29
+ "list_signature_campaigns_signatures_campaigns_get",
30
+ "list_signature_deployments_signatures_mailboxes_get",
31
+ "list_signature_members_signatures_members_get",
32
+ "list_signature_templates_signatures_templates_get",
33
+ "preview_saved_signature_template_signatures_templates__template_id__preview_post",
34
+ "preview_signature_campaign_signatures_campaigns_preview_post",
35
+ "preview_signature_setup_signatures_setup_preview_post",
36
+ "preview_signature_template_signatures_preview_post",
37
+ "push_signature_signatures_mailboxes__mailbox_id__push_post",
38
+ "push_signatures_signatures_mailboxes_push_post",
39
+ "restore_signature_signatures_mailboxes__mailbox_id__restore_post",
40
+ "set_default_signature_template_signatures_templates__template_id__set_default_post",
41
+ "update_signature_campaign_signatures_campaigns__campaign_id__patch",
42
+ "update_signature_settings_signatures_settings_put",
43
+ "update_signature_template_signatures_templates__template_id__patch"
44
+ ],
45
+ "components": [
46
+ {
47
+ "name": "EmailSignaturesScreen",
48
+ "file": "components/email-signatures-screen.tsx",
49
+ "purpose": "Finished email-signatures workspace: templates with a live preview, apply to mailboxes, the organisation default, mailboxes with push, restore and source, banner campaigns, the policy and the engagement report.",
50
+ "operations": [
51
+ "get_signature_settings_signatures_settings_get",
52
+ "list_signature_deployments_signatures_mailboxes_get",
53
+ "list_signature_templates_signatures_templates_get"
54
+ ],
55
+ "tiers": [
56
+ "read"
57
+ ]
58
+ },
59
+ {
60
+ "name": "SignatureTemplateForm",
61
+ "file": "components/signature-template-form.tsx",
62
+ "purpose": "Create or edit a signature template (layout, font, colour, blocks, placeholders) with a live preview; edit reads the full record first and a stale save is refused.",
63
+ "operations": [
64
+ "create_signature_template_signatures_templates_post",
65
+ "get_signature_template_signatures_templates__template_id__get",
66
+ "update_signature_template_signatures_templates__template_id__patch"
67
+ ],
68
+ "tiers": [
69
+ "read",
70
+ "write"
71
+ ]
72
+ },
73
+ {
74
+ "name": "SignatureBlockEditor",
75
+ "file": "components/signature-block-editor.tsx",
76
+ "purpose": "The ordered block list of a template: type, text, link, image, locked, required, placeholders, reorder and remove. A pure control that calls no operation.",
77
+ "operations": [],
78
+ "tiers": []
79
+ },
80
+ {
81
+ "name": "TemplatePreview",
82
+ "file": "components/signature-preview.tsx",
83
+ "purpose": "Render a draft or a stored template as a sample or as a real employee on a real mailbox, in full, compact or campaign form, or as plain text; the HTML is shown in a sandboxed frame (also exports SafeSignatureFrame).",
84
+ "operations": [
85
+ "list_mailboxes_mailboxes_get",
86
+ "list_signature_deployments_signatures_mailboxes_get",
87
+ "list_signature_members_signatures_members_get",
88
+ "preview_saved_signature_template_signatures_templates__template_id__preview_post",
89
+ "preview_signature_template_signatures_preview_post"
90
+ ],
91
+ "tiers": [
92
+ "read",
93
+ "write"
94
+ ]
95
+ },
96
+ {
97
+ "name": "SignatureAssignTemplate",
98
+ "file": "components/signature-assign-template.tsx",
99
+ "purpose": "Apply a template to chosen mailboxes, a department or every mailbox; confirmed with the number of mailboxes it really covers.",
100
+ "operations": [
101
+ "assign_signature_template_signatures_templates__template_id__assign_post",
102
+ "list_mailboxes_mailboxes_get",
103
+ "list_signature_deployments_signatures_mailboxes_get",
104
+ "list_signature_members_signatures_members_get"
105
+ ],
106
+ "tiers": [
107
+ "read",
108
+ "write"
109
+ ]
110
+ },
111
+ {
112
+ "name": "SignatureTemplateDetails",
113
+ "file": "components/signature-template-details.tsx",
114
+ "purpose": "One template's facts, make it the organisation default (confirmed, sized from the mailboxes that follow it) and archive it (confirmed; disabled while it is in use).",
115
+ "operations": [
116
+ "archive_signature_template_signatures_templates__template_id__delete",
117
+ "get_signature_settings_signatures_settings_get",
118
+ "list_signature_deployments_signatures_mailboxes_get",
119
+ "list_signature_members_signatures_members_get",
120
+ "set_default_signature_template_signatures_templates__template_id__set_default_post"
121
+ ],
122
+ "tiers": [
123
+ "read",
124
+ "write",
125
+ "destructive"
126
+ ]
127
+ },
128
+ {
129
+ "name": "SignatureMailboxes",
130
+ "file": "components/signature-mailboxes.tsx",
131
+ "purpose": "Every mailbox with its employee, template source and status; assign an employee, push (one or many), restore the old signature and change what a mailbox sends, each confirmed.",
132
+ "operations": [
133
+ "change_signature_source_signatures_mailboxes__mailbox_id__source_post",
134
+ "get_signature_settings_signatures_settings_get",
135
+ "list_mailboxes_mailboxes_get",
136
+ "list_signature_deployments_signatures_mailboxes_get",
137
+ "list_signature_members_signatures_members_get",
138
+ "list_signature_templates_signatures_templates_get",
139
+ "push_signature_signatures_mailboxes__mailbox_id__push_post",
140
+ "push_signatures_signatures_mailboxes_push_post",
141
+ "restore_signature_signatures_mailboxes__mailbox_id__restore_post"
142
+ ],
143
+ "tiers": [
144
+ "read",
145
+ "write"
146
+ ]
147
+ },
148
+ {
149
+ "name": "SignatureIdentityForm",
150
+ "file": "components/signature-identity-form.tsx",
151
+ "purpose": "Bind one mailbox to an employee: account and send-as derived from the choices, a dry-run setup check, then a confirmed takeover.",
152
+ "operations": [
153
+ "assign_signature_identity_signatures_assignments_post",
154
+ "list_signature_deployments_signatures_mailboxes_get",
155
+ "list_signature_members_signatures_members_get",
156
+ "list_signature_templates_signatures_templates_get",
157
+ "preview_signature_setup_signatures_setup_preview_post"
158
+ ],
159
+ "tiers": [
160
+ "read",
161
+ "write"
162
+ ]
163
+ },
164
+ {
165
+ "name": "SignaturePolicy",
166
+ "file": "components/signature-policy.tsx",
167
+ "purpose": "The organisation policy: off, managed or enforced, default and department templates, employee overrides, cold-send variant and native installation; a confirmed save of the changed fields.",
168
+ "operations": [
169
+ "get_signature_settings_signatures_settings_get",
170
+ "list_signature_deployments_signatures_mailboxes_get",
171
+ "list_signature_members_signatures_members_get",
172
+ "list_signature_templates_signatures_templates_get",
173
+ "update_signature_settings_signatures_settings_put"
174
+ ],
175
+ "tiers": [
176
+ "read",
177
+ "write"
178
+ ]
179
+ },
180
+ {
181
+ "name": "SignatureCampaigns",
182
+ "file": "components/signature-campaigns.tsx",
183
+ "purpose": "Banner campaigns with status, dates and priority; create and edit in a sheet.",
184
+ "operations": [
185
+ "list_signature_campaigns_signatures_campaigns_get"
186
+ ],
187
+ "tiers": [
188
+ "read"
189
+ ]
190
+ },
191
+ {
192
+ "name": "SignatureCampaignForm",
193
+ "file": "components/signature-campaign-form.tsx",
194
+ "purpose": "Create or edit a banner campaign (banner, dates, status, priority, who sees it), preview the banner and test which mailbox and recipients it would reach.",
195
+ "operations": [
196
+ "create_signature_campaign_signatures_campaigns_post",
197
+ "list_mailboxes_mailboxes_get",
198
+ "list_signature_deployments_signatures_mailboxes_get",
199
+ "list_signature_members_signatures_members_get",
200
+ "preview_signature_campaign_signatures_campaigns_preview_post",
201
+ "update_signature_campaign_signatures_campaigns__campaign_id__patch"
202
+ ],
203
+ "tiers": [
204
+ "read",
205
+ "write"
206
+ ]
207
+ },
208
+ {
209
+ "name": "SignatureReport",
210
+ "file": "components/signature-report.tsx",
211
+ "purpose": "Impressions and clicks by mailbox and campaign, with the limits the API states about the numbers.",
212
+ "operations": [
213
+ "get_signature_report_signatures_reports_get",
214
+ "list_mailboxes_mailboxes_get",
215
+ "list_signature_campaigns_signatures_campaigns_get",
216
+ "list_signature_deployments_signatures_mailboxes_get"
217
+ ],
218
+ "tiers": [
219
+ "read"
220
+ ]
221
+ }
222
+ ],
223
+ "hooks": [
224
+ {
225
+ "name": "useSignaturesData",
226
+ "file": "hooks/use-signatures-data.ts",
227
+ "purpose": "Shared cached reads: templates, one template, members, mailbox deployments, the policy, campaigns, and mailboxes merged with their deployments (the mailbox list is read once at the API's limit of 500 and says when it may be longer).",
228
+ "operations": [
229
+ "get_signature_settings_signatures_settings_get",
230
+ "get_signature_template_signatures_templates__template_id__get",
231
+ "list_mailboxes_mailboxes_get",
232
+ "list_signature_campaigns_signatures_campaigns_get",
233
+ "list_signature_deployments_signatures_mailboxes_get",
234
+ "list_signature_members_signatures_members_get",
235
+ "list_signature_templates_signatures_templates_get"
236
+ ]
237
+ }
238
+ ],
239
+ "lib": [
240
+ {
241
+ "file": "lib/signatures-types.ts",
242
+ "purpose": "Template, policy, deployment and campaign types; the API's exact vocabularies (block kinds, layouts, fonts, modes, statuses, sources); the placeholder list; template rules checked before a save; local-time helpers for campaign dates."
243
+ }
244
+ ],
245
+ "recipes": [
246
+ {
247
+ "file": "recipes/create-a-template-and-make-it-default.ts",
248
+ "title": "Create a signature template and make it the organisation default",
249
+ "when": "First-time setup; making it the default changes what mailboxes send, so a person confirms."
250
+ },
251
+ {
252
+ "file": "recipes/assign-a-signature-to-a-new-hire.ts",
253
+ "title": "Give a new hire's mailbox a managed signature",
254
+ "when": "Onboarding; a takeover of the mailbox's signature that a person agrees to."
255
+ },
256
+ {
257
+ "file": "recipes/signature-engagement-report.ts",
258
+ "title": "Report signature impressions and clicks",
259
+ "when": "A weekly digest or a dashboard backend."
260
+ }
261
+ ],
262
+ "prerequisites": [
263
+ {
264
+ "id": "mailboxes",
265
+ "description": "Mailboxes connected in the app (Google or Microsoft) or added through the mailboxes block. A signature is bound to a mailbox.",
266
+ "where": "api",
267
+ "verify": "GET /api/v1/mailboxes lists the mailbox."
268
+ },
269
+ {
270
+ "id": "directory-employees",
271
+ "description": "The people who sign must be team members with an email address in the directory. An employee without an email cannot be assigned.",
272
+ "where": "api",
273
+ "verify": "GET /api/v1/signatures/members lists them."
274
+ },
275
+ {
276
+ "id": "workspace-signature-access",
277
+ "description": "Installing a signature inside a Google account needs the Google Workspace integration with the signature permission granted by a Workspace admin in the app. A deployment that stops at needs_admin_grant is missing it. Without native installation the signature is applied when mail is sent from the platform.",
278
+ "where": "app",
279
+ "verify": "A deployment reaches an installed status instead of needs_admin_grant."
280
+ },
281
+ {
282
+ "id": "signature-scopes",
283
+ "description": "The key needs signatures:read, signatures:write and signatures:delete (archive). Listing mailboxes needs campaigns:read.",
284
+ "where": "api",
285
+ "verify": "g8.api.me.describeCurrentKey() lists the scopes."
286
+ },
287
+ {
288
+ "id": "proxy-allowlist",
289
+ "description": "Add \"signatures\" and \"mailboxes\" to allowedPrefixes in app/api/g8/[...path]/route.ts.",
290
+ "where": "app",
291
+ "verify": "The route file's allowedPrefixes contains them."
292
+ }
293
+ ],
294
+ "scopes": [
295
+ "campaigns:read",
296
+ "signatures:delete",
297
+ "signatures:read",
298
+ "signatures:write"
299
+ ],
300
+ "defaults": [
301
+ {
302
+ "decision": "New template",
303
+ "default": "Classic stacked layout, Arial, text colour #222222, brand kit colour and font, one required locked identity block with the employee's name and title",
304
+ "askHuman": false
305
+ },
306
+ {
307
+ "decision": "Which mailboxes get a template",
308
+ "default": "None: a person always chooses the mailboxes, a department or everyone, and confirms the count",
309
+ "askHuman": true
310
+ },
311
+ {
312
+ "decision": "Policy mode",
313
+ "default": "Leave it as it is; turning management on needs a default template, enforcing needs every active mailbox assigned",
314
+ "askHuman": true
315
+ },
316
+ {
317
+ "decision": "Assigning an employee to a mailbox",
318
+ "default": "Account = the employee's directory email, send-as = the mailbox address; only after a person agrees to the takeover",
319
+ "askHuman": true
320
+ },
321
+ {
322
+ "decision": "Stopping a campaign",
323
+ "default": "Set it to Paused (the API cannot delete a campaign)",
324
+ "askHuman": false
325
+ },
326
+ {
327
+ "decision": "Removing a template",
328
+ "default": "Archive it, after giving its mailboxes another template",
329
+ "askHuman": false
330
+ },
331
+ {
332
+ "decision": "After editing a template",
333
+ "default": "Push the mailboxes that use it from the Mailboxes tab",
334
+ "askHuman": false
335
+ }
336
+ ],
337
+ "peerDependencies": {
338
+ "react": ">=18",
339
+ "lucide-react": ">=0.400.0"
340
+ }
341
+ }
@@ -0,0 +1,166 @@
1
+ "use client";
2
+
3
+ /**
4
+ * EmailSignaturesScreen: the finished workspace for managed email signatures. No props needed.
5
+ *
6
+ * Composes: ScreenLayout (title, tabs, stats), Toolbar (search), SplitView + DetailPanel (the selected template, deep link
7
+ * `?id=`), FormSheet (new template via SignatureTemplateForm), TemplatePreview, SignatureAssignTemplate,
8
+ * SignatureTemplateDetails, SignatureMailboxes, SignatureCampaigns, SignaturePolicy and SignatureReport.
9
+ *
10
+ * Tabs (`?tab=`): Templates (list and detail), Mailboxes, Campaigns, Policy, Report. A template's detail (`?id=`) has Preview,
11
+ * Edit, Use on mailboxes and Details; `&view=full` shows it as a full page.
12
+ *
13
+ * User flows: see every template (search; the list is complete because the API does not page it); create one with blocks,
14
+ * placeholders and a live preview; open it and preview it as a real employee on a real mailbox, in full, compact or campaign
15
+ * form, or as plain text; edit it (sends only after the full record has loaded; a stale save is refused and explained);
16
+ * apply it to chosen mailboxes, a department or everyone (confirmed with the real number of mailboxes); make it the
17
+ * organisation default or archive it (both confirmed). On the Mailboxes tab: assign an employee to a mailbox (check the setup
18
+ * first), push, restore the old signature and change what a mailbox sends, one by one or in bulk, each confirmed. Campaigns
19
+ * add a banner for a time window and can be previewed and tested against a mailbox and recipients. The Policy tab turns
20
+ * management off, on or enforced, sets the default and department templates. The Report tab reads impressions and clicks.
21
+ * The API has no variables list, template delete (only archive), campaign delete, asset upload or employee self-service
22
+ * (see the README for the gaps).
23
+ *
24
+ * SDK operations: none directly. Every call lives in the composed parts, which confirm every change to what a mailbox sends.
25
+ */
26
+
27
+ import { useState } from "react";
28
+ import type { ReactNode } from "react";
29
+ import { PenLine, Plus } from "lucide-react";
30
+ import { Button, Skeleton } from "@graph8/sdk/ui";
31
+ import { ApiError } from "@/g8/components/api-error";
32
+ import { EmptyState } from "@/g8/components/empty-state";
33
+ import { DetailPanel } from "@/g8/components/screen/detail-panel";
34
+ import { FormSheet } from "@/g8/components/screen/form-sheet";
35
+ import { ScreenLayout } from "@/g8/components/screen/screen-layout";
36
+ import { SplitView } from "@/g8/components/screen/split-view";
37
+ import { StatusPill } from "@/g8/components/screen/status-pill";
38
+ import { Toolbar } from "@/g8/components/screen/toolbar";
39
+ import { useUrlState } from "@/g8/hooks/use-url-state";
40
+ import { plural } from "@/g8/lib/plural";
41
+ import { useSignatureDeployments, useSignaturePolicy, useSignatureTemplates } from "../hooks/use-signatures-data";
42
+ import { LAYOUTS, POLICY_MODES, isManaged, templateName } from "../lib/signatures-types";
43
+ import type { SignatureTemplate } from "../lib/signatures-types";
44
+ import { SignatureAssignTemplate } from "./signature-assign-template";
45
+ import { SignatureCampaigns } from "./signature-campaigns";
46
+ import { SignatureMailboxes } from "./signature-mailboxes";
47
+ import { SignaturePolicy } from "./signature-policy";
48
+ import { SignatureReport } from "./signature-report";
49
+ import { SignatureTemplateDetails } from "./signature-template-details";
50
+ import { SignatureTemplateForm } from "./signature-template-form";
51
+ import { TemplatePreview } from "./signature-preview";
52
+
53
+ export interface EmailSignaturesScreenProps {
54
+ renderRowActions?: (template: SignatureTemplate) => ReactNode;
55
+ renderDetailActions?: (template: SignatureTemplate) => ReactNode;
56
+ extraDetailTabs?: { id: string; label: string; render: (template: SignatureTemplate) => ReactNode }[];
57
+ toolbarActions?: ReactNode;
58
+ className?: string;
59
+ }
60
+
61
+ type Tab = "templates" | "mailboxes" | "campaigns" | "policy" | "report";
62
+ const TABS: Tab[] = ["templates", "mailboxes", "campaigns", "policy", "report"];
63
+
64
+ export function EmailSignaturesScreen({ renderRowActions, renderDetailActions, extraDetailTabs, toolbarActions, className }: EmailSignaturesScreenProps) {
65
+ const [id, setId] = useUrlState("id", "");
66
+ const [view, setView] = useUrlState("view", "");
67
+ const [tabParam, setTabParam] = useUrlState("tab", "templates");
68
+ const tab = (TABS.includes(tabParam as Tab) ? tabParam : "templates") as Tab;
69
+ const [search, setSearch] = useState("");
70
+ const [creating, setCreating] = useState(false);
71
+ const [savedVersion, setSavedVersion] = useState<{ id: string; version: number } | null>(null);
72
+ const list = useSignatureTemplates();
73
+ const deployments = useSignatureDeployments();
74
+ const policy = useSignaturePolicy();
75
+
76
+ const all = list.data ?? [];
77
+ const q = search.trim().toLowerCase();
78
+ const shown = all.filter((t) => !q || templateName(t).toLowerCase().includes(q));
79
+ const selected = all.find((t) => t.id === id);
80
+ const defaultId = policy.data?.data.default_template_id;
81
+ const closeDetail = (): void => { setId(null); setView(null); };
82
+ const rows = deployments.data ?? [];
83
+
84
+ const listBody = list.error && !list.data ? <ApiError error={list.error} title="Could not load templates" onRetry={() => void list.refetch()} /> : !list.data ? (
85
+ <div aria-busy="true" className="grid gap-2"><Skeleton className="h-14 w-full" /><Skeleton className="h-14 w-full" /><Skeleton className="h-14 w-full" /></div>
86
+ ) : shown.length === 0 ? (
87
+ <EmptyState icon={<PenLine className="size-8" />} title={all.length === 0 ? "No signature templates yet" : "No templates match"} description={all.length === 0 ? "A template is the shared design of your team's email signatures. Create one, then assign it to mailboxes." : "Try another search."} action={all.length === 0 ? <Button onClick={() => setCreating(true)}>Create your first template</Button> : undefined} />
88
+ ) : (
89
+ <>
90
+ <p role="status" className="text-muted-foreground mb-2 text-xs">{shown.length === all.length ? `All ${plural(all.length, "template")}` : `${shown.length.toLocaleString()} of ${plural(all.length, "template")}`}</p>
91
+ <ul className="grid gap-2">
92
+ {shown.map((t) => (
93
+ <li key={t.id} className={`flex flex-wrap items-center justify-between gap-2 rounded-md border p-3 ${t.id === id ? "bg-muted" : ""}`}>
94
+ <button type="button" className="min-w-0 flex-1 text-left" onClick={() => setId(t.id)}>
95
+ <span className="block truncate font-medium">{templateName(t)}</span>
96
+ <span className="text-muted-foreground block truncate text-xs">{LAYOUTS.find((l) => l.value === t.data?.layout)?.label ?? "Layout unknown"} · {plural((t.data?.blocks ?? []).length, "block")} · version {t.version}</span>
97
+ </button>
98
+ {t.id === defaultId ? <StatusPill tone="positive">Default</StatusPill> : null}
99
+ {renderRowActions?.(t)}
100
+ </li>
101
+ ))}
102
+ </ul>
103
+ </>
104
+ );
105
+
106
+ const detail = selected ? (
107
+ <DetailPanel
108
+ title={templateName(selected)}
109
+ subtitle={LAYOUTS.find((l) => l.value === selected.data?.layout)?.label}
110
+ badges={selected.id === defaultId ? <StatusPill tone="positive">Organisation default</StatusPill> : undefined}
111
+ actions={renderDetailActions?.(selected)}
112
+ onClose={closeDetail}
113
+ onExpand={() => setView("full")}
114
+ onCollapse={view === "full" ? () => setView(null) : undefined}
115
+ tabs={[
116
+ { id: "preview", label: "Preview", content: <TemplatePreview key={`${selected.id}:${selected.version}`} templateId={selected.id} /> },
117
+ { id: "edit", label: "Edit", content: (
118
+ <div className="grid gap-3">
119
+ {savedVersion?.id === selected.id && savedVersion.version === selected.version ? <p role="status" className="text-sm">Template saved as version {selected.version}. To install it again on the mailboxes that use it, push them from the Mailboxes tab.</p> : null}
120
+ <SignatureTemplateForm key={selected.id} template={selected} onSaved={(saved) => setSavedVersion({ id: saved.id, version: saved.version })} />
121
+ </div>
122
+ ) },
123
+ { id: "use", label: "Use on mailboxes", content: <SignatureAssignTemplate key={selected.id} template={selected} /> },
124
+ { id: "details", label: "Details", content: <SignatureTemplateDetails template={selected} onArchived={closeDetail} /> },
125
+ ...(extraDetailTabs ?? []).map((t) => ({ id: t.id, label: t.label, content: t.render(selected) })),
126
+ ]}
127
+ />
128
+ ) : null;
129
+
130
+ const templatesTab = (
131
+ <SplitView
132
+ list={<div className="grid gap-3"><Toolbar search={{ value: search, onChange: setSearch, placeholder: "Search templates" }} actions={toolbarActions} />{listBody}</div>}
133
+ detail={detail}
134
+ detailOpen={Boolean(selected)}
135
+ onCloseDetail={closeDetail}
136
+ expanded={view === "full"}
137
+ onExpandedChange={(e) => setView(e ? "full" : null)}
138
+ detailWidth="xl"
139
+ />
140
+ );
141
+
142
+ const mode = POLICY_MODES.find((m) => m.value === policy.data?.data.mode)?.label;
143
+ return (
144
+ <ScreenLayout
145
+ className={className}
146
+ title="Email signatures"
147
+ description="Design one signature for the team and keep every mailbox on it."
148
+ icon={<PenLine className="size-5" />}
149
+ actions={<Button size="sm" onClick={() => { setTabParam(null); setCreating(true); }}><Plus className="size-4" />New template</Button>}
150
+ tabs={[{ id: "templates", label: "Templates", count: list.data ? all.length : undefined }, { id: "mailboxes", label: "Mailboxes" }, { id: "campaigns", label: "Campaigns" }, { id: "policy", label: "Policy" }, { id: "report", label: "Report" }]}
151
+ activeTab={tab}
152
+ onTabChange={(next) => { setTabParam(next === "templates" ? null : next); closeDetail(); }}
153
+ stats={tab === "templates" ? [
154
+ { label: "Templates", value: list.data ? all.length.toLocaleString() : "..." },
155
+ { label: "Managed mailboxes", value: deployments.data ? rows.filter((d) => isManaged(d)).length.toLocaleString() : "..." },
156
+ { label: "Need attention", value: deployments.data ? rows.filter((d) => d.alert).length.toLocaleString() : "...", tone: rows.some((d) => d.alert) ? "negative" : undefined },
157
+ { label: "Management", value: mode ?? (policy.data ? "Not set" : policy.error ? "Unavailable" : "...") },
158
+ ] : undefined}
159
+ >
160
+ {tab === "templates" ? templatesTab : tab === "mailboxes" ? <SignatureMailboxes /> : tab === "campaigns" ? <SignatureCampaigns /> : tab === "policy" ? <SignaturePolicy /> : <SignatureReport />}
161
+ <FormSheet open={creating} onOpenChange={setCreating} width="xl" title="New signature template" description="Design the signature once. Nothing reaches a mailbox until you apply it.">
162
+ {creating ? <SignatureTemplateForm onCancel={() => setCreating(false)} onSaved={(created) => { setCreating(false); setId(created.id); }} /> : null}
163
+ </FormSheet>
164
+ </ScreenLayout>
165
+ );
166
+ }
@@ -0,0 +1,119 @@
1
+ "use client";
2
+
3
+ /**
4
+ * SignatureAssignTemplate: point mailboxes at a template. Choose the mailboxes one by one, every mailbox of a department, or
5
+ * every mailbox; the API then queues a re-install on each.
6
+ *
7
+ * SDK operations, in order (the mailbox, member and deployment reads come from the shared hooks):
8
+ * 1. assignSignatureTemplate (POST /signatures/templates/{template_id}/assign) write replaces the signature the chosen mailboxes SEND:
9
+ * ConfirmSpendDialog (external) first, sized from the mailboxes the choice really covers.
10
+ * Targets are exclusive (mailbox ids, a department, or all mailboxes) and every target must already have an employee
11
+ * assigned (Mailboxes tab); the API refuses the whole call otherwise, so those mailboxes are shown disabled with the reason.
12
+ * "All mailboxes" is only offered when every active mailbox is assigned and the list is complete. The result says how many
13
+ * mailboxes were queued; progress then shows in the Mailboxes tab.
14
+ */
15
+
16
+ import { useState } from "react";
17
+ import { Button } from "@graph8/sdk/ui";
18
+ import { ApiError } from "@/g8/components/api-error";
19
+ import { ConfirmSpendDialog } from "@/g8/components/confirm-spend-dialog";
20
+ import { FirstNotice } from "@/g8/components/paging-notices";
21
+ import { StatusPill } from "@/g8/components/screen/status-pill";
22
+ import { g8Post } from "@/g8/lib/g8-client";
23
+ import { useG8Mutation } from "@/g8/hooks/use-g8-mutation";
24
+ import { plural } from "@/g8/lib/plural";
25
+ import { MAILBOX_LIMIT, useSignatureMailboxes, useSignatureMembers } from "../hooks/use-signatures-data";
26
+ import { isManaged, templateName } from "../lib/signatures-types";
27
+ import type { SignatureTemplate } from "../lib/signatures-types";
28
+
29
+ export interface SignatureAssignTemplateProps {
30
+ template: SignatureTemplate;
31
+ onAssigned?: (count: number) => void;
32
+ }
33
+
34
+ type Mode = "mailboxes" | "department" | "all";
35
+ interface Result { count: number }
36
+
37
+ const SELECT = "border-input bg-background h-9 rounded-md border px-2 text-sm";
38
+
39
+ export function SignatureAssignTemplate({ template, onAssigned }: SignatureAssignTemplateProps) {
40
+ const box = useSignatureMailboxes();
41
+ const members = useSignatureMembers();
42
+ const [mode, setMode] = useState<Mode>("mailboxes");
43
+ const [picked, setPicked] = useState<number[]>([]);
44
+ const [department, setDepartment] = useState("");
45
+ const [confirm, setConfirm] = useState(false);
46
+ const [done, setDone] = useState<Result | null>(null);
47
+
48
+ const assigned = box.mailboxes.filter((m) => isManaged(m.deployment));
49
+ const unassigned = box.mailboxes.filter((m) => !isManaged(m.deployment));
50
+ const deptOf = (memberId: string | undefined): string | null => members.data?.find((x) => x.id === memberId)?.department ?? null;
51
+ const departments = [...new Set(assigned.map((m) => deptOf(m.deployment?.assignment?.member_id)).filter((d): d is string => Boolean(d)))].sort();
52
+ const inDepartment = assigned.filter((m) => deptOf(m.deployment?.assignment?.member_id) === department);
53
+ const allowAll = unassigned.length === 0 && !box.truncated && !box.mailboxesError && box.mailboxes.length > 0;
54
+ const covered = mode === "mailboxes" ? picked.filter((id) => assigned.some((m) => m.id === id)).length : mode === "department" ? inDepartment.length : box.mailboxes.length;
55
+ const ready = covered > 0 && (mode !== "department" || department !== "") && (mode !== "all" || allowAll);
56
+
57
+ const apply = useG8Mutation(async (): Promise<Result> => {
58
+ const body = mode === "mailboxes" ? { mailbox_ids: picked.filter((id) => assigned.some((m) => m.id === id)) } : mode === "department" ? { department } : { all_mailboxes: true };
59
+ return (await g8Post<Result>(`/signatures/templates/${encodeURIComponent(template.id)}/assign`, body)).data;
60
+ }, {
61
+ onSuccess: (r) => { setConfirm(false); setDone(r); setPicked([]); onAssigned?.(r.count); },
62
+ onError: () => setConfirm(false),
63
+ invalidates: [["signatures", "deployments"]],
64
+ });
65
+
66
+ if (box.loading) return <p className="text-muted-foreground text-sm" aria-busy="true">Loading mailboxes</p>;
67
+ if (box.error) return <ApiError error={box.error} title="Could not load mailboxes" onRetry={box.refetch} />;
68
+
69
+ return (
70
+ <div className="grid gap-3">
71
+ <p className="text-muted-foreground text-sm">Choose which mailboxes send {templateName(template)}. Each mailbox keeps its employee; only the template changes.</p>
72
+ <fieldset className="grid gap-1 text-sm">
73
+ <legend className="mb-1 font-medium">Apply to</legend>
74
+ <label className="flex items-center gap-2"><input type="radio" name="g8-sig-target" checked={mode === "mailboxes"} onChange={() => setMode("mailboxes")} />Chosen mailboxes</label>
75
+ <label className="flex items-center gap-2"><input type="radio" name="g8-sig-target" checked={mode === "department"} onChange={() => setMode("department")} />Every mailbox in a department</label>
76
+ <label className="flex items-center gap-2"><input type="radio" name="g8-sig-target" checked={mode === "all"} disabled={!allowAll} onChange={() => setMode("all")} />Every mailbox{allowAll ? "" : unassigned.length > 0 ? ` (${plural(unassigned.length, "mailbox")} still without an employee)` : " (the full list could not be confirmed)"}</label>
77
+ </fieldset>
78
+ {box.mailboxesError ? <ApiError compact error={box.mailboxesError} title="Mailboxes without a signature are not listed" onRetry={box.refetch} /> : null}
79
+ {mode === "mailboxes" ? (
80
+ <ul className="grid gap-1" aria-label="Mailboxes">
81
+ {box.mailboxes.map((m) => {
82
+ const ok = isManaged(m.deployment);
83
+ return (
84
+ <li key={m.id} className="flex items-center gap-2 text-sm">
85
+ <input type="checkbox" id={`g8-sig-mb-${m.id}`} disabled={!ok} checked={picked.includes(m.id)} onChange={(e) => setPicked(e.target.checked ? [...picked, m.id] : picked.filter((id) => id !== m.id))} />
86
+ <label htmlFor={`g8-sig-mb-${m.id}`}>{m.email}</label>
87
+ {!ok ? <StatusPill tone="neutral">No employee assigned</StatusPill> : null}
88
+ </li>
89
+ );
90
+ })}
91
+ </ul>
92
+ ) : null}
93
+ {mode === "department" ? (
94
+ <div className="grid gap-1">
95
+ <select aria-label="Department" className={SELECT} value={department} onChange={(e) => setDepartment(e.target.value)}>
96
+ <option value="">Choose a department</option>
97
+ {departments.map((d) => <option key={d} value={d}>{d}</option>)}
98
+ </select>
99
+ {departments.length === 0 ? <p className="text-muted-foreground text-xs">No assigned employee has a department yet.</p> : null}
100
+ </div>
101
+ ) : null}
102
+ <FirstNotice shown={box.mailboxes.length} limit={MAILBOX_LIMIT} noun="mailboxes" force={box.truncated} />
103
+ {apply.error ? <ApiError error={apply.error} title="Could not apply the template" /> : null}
104
+ {done ? <p role="status" className="text-sm">Queued {plural(done.count, "mailbox")} to install {templateName(template)}. Follow progress in the Mailboxes tab.</p> : null}
105
+ <div><Button type="button" disabled={!ready} onClick={() => setConfirm(true)}>Apply to {plural(covered, "mailbox")}</Button></div>
106
+ <ConfirmSpendDialog
107
+ open={confirm}
108
+ tier="external"
109
+ title={`Apply ${templateName(template)} to ${plural(covered, "mailbox")}?`}
110
+ affected={covered}
111
+ description="These mailboxes will send this signature on new emails. Emails already sent do not change. A mailbox can be given its old signature back from the Mailboxes tab unless the policy is enforced."
112
+ confirmLabel="Apply template"
113
+ confirming={apply.loading}
114
+ onCancel={() => setConfirm(false)}
115
+ onConfirm={() => void apply.mutate(undefined)}
116
+ />
117
+ </div>
118
+ );
119
+ }