@graph8/sdk 0.361.0 → 0.370.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 (388) hide show
  1. package/README.md +14 -10
  2. package/blocks/_foundation/README.md +172 -1
  3. package/blocks/_foundation/block.json +234 -13
  4. package/blocks/_foundation/components/api-error.tsx +71 -25
  5. package/blocks/_foundation/components/brand-provider.tsx +23 -0
  6. package/blocks/_foundation/components/confirmed-action.tsx +90 -0
  7. package/blocks/_foundation/components/connect-graph8.tsx +280 -0
  8. package/blocks/_foundation/components/empty-state.tsx +39 -7
  9. package/blocks/_foundation/components/screen/bar-list.tsx +71 -0
  10. package/blocks/_foundation/components/screen/detail-panel.tsx +114 -0
  11. package/blocks/_foundation/components/screen/entity-avatar.tsx +56 -0
  12. package/blocks/_foundation/components/screen/form-sheet.tsx +73 -0
  13. package/blocks/_foundation/components/screen/index.ts +22 -0
  14. package/blocks/_foundation/components/screen/key-value-list.tsx +65 -0
  15. package/blocks/_foundation/components/screen/record-link.tsx +76 -0
  16. package/blocks/_foundation/components/screen/screen-layout.tsx +124 -0
  17. package/blocks/_foundation/components/screen/section-card.tsx +47 -0
  18. package/blocks/_foundation/components/screen/sparkline.tsx +77 -0
  19. package/blocks/_foundation/components/screen/split-view.tsx +125 -0
  20. package/blocks/_foundation/components/screen/stat-strip.tsx +121 -0
  21. package/blocks/_foundation/components/screen/status-pill.tsx +104 -0
  22. package/blocks/_foundation/components/screen/time-series-chart-recharts.tsx +65 -0
  23. package/blocks/_foundation/components/screen/time-series-chart.tsx +32 -0
  24. package/blocks/_foundation/components/screen/time-series-format.ts +57 -0
  25. package/blocks/_foundation/components/screen/toolbar.tsx +144 -0
  26. package/blocks/_foundation/hooks/use-brand.ts +52 -0
  27. package/blocks/_foundation/hooks/use-g8-mutation.ts +23 -0
  28. package/blocks/_foundation/hooks/use-g8-query.ts +127 -1
  29. package/blocks/_foundation/hooks/use-paginated.ts +120 -0
  30. package/blocks/_foundation/hooks/use-row-activation.ts +57 -0
  31. package/blocks/_foundation/hooks/use-url-state.ts +74 -0
  32. package/blocks/_foundation/lib/g8-cache.ts +454 -0
  33. package/blocks/_foundation/lib/g8-client.ts +1 -1
  34. package/blocks/_foundation/lib/plural.ts +23 -0
  35. package/blocks/_foundation/server/connect-route.ts +15 -0
  36. package/blocks/_foundation/server/connect.ts +127 -0
  37. package/blocks/_foundation/server/local-key.ts +70 -0
  38. package/blocks/_foundation/server/proxy.ts +103 -3
  39. package/blocks/_foundation/server/route.ts +16 -4
  40. package/blocks/agents/README.md +14 -0
  41. package/blocks/agents/block.json +33 -1
  42. package/blocks/agents/components/agent-builder.tsx +13 -8
  43. package/blocks/agents/components/agent-knowledge-panel.tsx +2 -1
  44. package/blocks/agents/components/agent-run-detail.tsx +102 -0
  45. package/blocks/agents/components/agent-runs.tsx +16 -7
  46. package/blocks/agents/components/agents-screen.tsx +184 -0
  47. package/blocks/analytics/README.md +13 -0
  48. package/blocks/analytics/block.json +45 -1
  49. package/blocks/analytics/components/analytics-screen.tsx +209 -0
  50. package/blocks/analytics/components/leaderboard.tsx +14 -7
  51. package/blocks/analytics/components/report-builder.tsx +23 -9
  52. package/blocks/analytics/components/report-detail.tsx +84 -0
  53. package/blocks/analytics/components/trend-chart.tsx +62 -0
  54. package/blocks/appointments/README.md +21 -1
  55. package/blocks/appointments/block.json +43 -2
  56. package/blocks/appointments/components/availability-editor.tsx +17 -5
  57. package/blocks/appointments/components/event-type-editor.tsx +2 -1
  58. package/blocks/appointments/components/event-type-related.tsx +77 -0
  59. package/blocks/appointments/components/meeting-list.tsx +14 -6
  60. package/blocks/appointments/components/meetings-screen.tsx +157 -0
  61. package/blocks/appointments/components/scheduling-screen.tsx +122 -0
  62. package/blocks/appointments/hooks/use-event-types.ts +17 -0
  63. package/blocks/block.schema.json +18 -0
  64. package/blocks/block.types.ts +26 -0
  65. package/blocks/campaigns/README.md +41 -11
  66. package/blocks/campaigns/block.json +105 -42
  67. package/blocks/campaigns/components/campaign-assets.tsx +16 -5
  68. package/blocks/campaigns/components/campaign-launch-step.tsx +102 -19
  69. package/blocks/campaigns/components/campaign-list.tsx +7 -3
  70. package/blocks/campaigns/components/campaign-wizard.tsx +43 -10
  71. package/blocks/campaigns/components/campaigns-screen.tsx +267 -0
  72. package/blocks/campaigns/components/icp-detail.tsx +154 -0
  73. package/blocks/campaigns/components/icp-editor.tsx +15 -15
  74. package/blocks/campaigns/components/persona-detail.tsx +172 -0
  75. package/blocks/campaigns/components/persona-editor.tsx +14 -11
  76. package/blocks/campaigns/lib/campaigns-utils.ts +134 -1
  77. package/blocks/campaigns/recipes/attach-audience-and-launch.ts +16 -3
  78. package/blocks/campaigns/recipes/generate-ideas-and-create-campaign.ts +8 -4
  79. package/blocks/coach/README.md +10 -0
  80. package/blocks/coach/block.json +16 -1
  81. package/blocks/coach/components/coach-screen.tsx +222 -0
  82. package/blocks/copilot/README.md +13 -0
  83. package/blocks/copilot/block.json +14 -1
  84. package/blocks/copilot/components/copilot-panel.tsx +14 -5
  85. package/blocks/copilot/components/copilot-screen.tsx +148 -0
  86. package/blocks/copilot/components/copilot-team-chat.tsx +7 -5
  87. package/blocks/crm/README.md +28 -0
  88. package/blocks/crm/block.json +58 -2
  89. package/blocks/crm/components/companies-screen.tsx +345 -0
  90. package/blocks/crm/components/company-detail.tsx +8 -6
  91. package/blocks/crm/components/company-table.tsx +11 -4
  92. package/blocks/crm/components/contact-detail.tsx +6 -3
  93. package/blocks/crm/components/contact-table.tsx +10 -3
  94. package/blocks/crm/components/contacts-screen.tsx +359 -0
  95. package/blocks/crm/components/dedupe-review.tsx +7 -5
  96. package/blocks/crm/components/import-wizard.tsx +4 -2
  97. package/blocks/crm/components/notes-panel.tsx +4 -4
  98. package/blocks/crm/components/record-form.tsx +5 -3
  99. package/blocks/crm/components/task-list.tsx +4 -4
  100. package/blocks/crm/components/tasks-screen.tsx +379 -0
  101. package/blocks/crm/hooks/use-custom-fields.ts +6 -1
  102. package/blocks/crm/hooks/use-page-query.ts +7 -1
  103. package/blocks/crm/lib/crm-types.ts +12 -2
  104. package/blocks/crm/lib/screen-parts.tsx +105 -0
  105. package/blocks/deals/README.md +34 -3
  106. package/blocks/deals/block.json +45 -4
  107. package/blocks/deals/components/deal-detail.tsx +27 -13
  108. package/blocks/deals/components/deal-related.tsx +87 -0
  109. package/blocks/deals/components/deals-screen.tsx +298 -0
  110. package/blocks/deals/components/pipeline-board.tsx +4 -2
  111. package/blocks/deals/components/stage-editor.tsx +4 -4
  112. package/blocks/deals/hooks/use-default-owner.ts +60 -0
  113. package/blocks/deals/hooks/use-pipeline-deals.ts +5 -1
  114. package/blocks/deals/hooks/use-pipelines.ts +1 -1
  115. package/blocks/deals/lib/deals-types.ts +14 -0
  116. package/blocks/dialer/README.md +34 -2
  117. package/blocks/dialer/block.json +67 -1
  118. package/blocks/dialer/components/call-contact-button.tsx +252 -0
  119. package/blocks/dialer/components/call-log-screen.tsx +205 -0
  120. package/blocks/dialer/components/call-log.tsx +7 -3
  121. package/blocks/dialer/components/call-queue.tsx +1 -1
  122. package/blocks/dialer/components/dialer-screen.tsx +319 -0
  123. package/blocks/dialer/components/dialer-session-detail.tsx +153 -0
  124. package/blocks/dialer/components/live-calls-table.tsx +7 -3
  125. package/blocks/dialer/components/session-start-form.tsx +4 -2
  126. package/blocks/dialer/components/softphone.tsx +3 -1
  127. package/blocks/enrichment/README.md +14 -2
  128. package/blocks/enrichment/block.json +32 -4
  129. package/blocks/enrichment/components/bulk-enrich-panel.tsx +10 -5
  130. package/blocks/enrichment/components/email-verify-badge.tsx +28 -8
  131. package/blocks/enrichment/components/enrich-button.tsx +32 -9
  132. package/blocks/enrichment/components/enrichment-job-detail.tsx +78 -0
  133. package/blocks/enrichment/components/enrichment-screen.tsx +288 -0
  134. package/blocks/enrichment/components/waterfall-config.tsx +39 -10
  135. package/blocks/enrichment/recipes/waterfall-pipeline.ts +3 -2
  136. package/blocks/forms/README.md +12 -0
  137. package/blocks/forms/block.json +39 -17
  138. package/blocks/forms/components/form-builder.tsx +3 -1
  139. package/blocks/forms/components/form-embed.tsx +3 -1
  140. package/blocks/forms/components/forms-screen.tsx +353 -0
  141. package/blocks/forms/components/submissions-table.tsx +16 -6
  142. package/blocks/inbox/README.md +27 -3
  143. package/blocks/inbox/block.json +14 -2
  144. package/blocks/inbox/components/inbox-list.tsx +7 -3
  145. package/blocks/inbox/components/inbox-screen.tsx +294 -27
  146. package/blocks/inbox/components/reply-composer.tsx +65 -9
  147. package/blocks/inbox/components/tag-and-assign.tsx +4 -2
  148. package/blocks/inbox/hooks/use-inbox-thread.ts +1 -1
  149. package/blocks/inbox/hooks/use-inbox-threads.ts +1 -0
  150. package/blocks/inbox/lib/inbox-types.ts +47 -1
  151. package/blocks/inbox/recipes/01-triage-and-reply.ts +12 -2
  152. package/blocks/integrations/README.md +9 -0
  153. package/blocks/integrations/block.json +46 -1
  154. package/blocks/integrations/components/crm-detail.tsx +100 -0
  155. package/blocks/integrations/components/integration-list.tsx +9 -4
  156. package/blocks/integrations/components/integrations-screen.tsx +135 -0
  157. package/blocks/integrations/components/sync-status.tsx +5 -3
  158. package/blocks/integrations/components/webhook-detail.tsx +160 -0
  159. package/blocks/integrations/components/webhook-manager.tsx +13 -8
  160. package/blocks/integrations/lib/integrations-utils.ts +6 -1
  161. package/blocks/intent/README.md +14 -0
  162. package/blocks/intent/block.json +27 -1
  163. package/blocks/intent/components/intent-feed.tsx +5 -2
  164. package/blocks/intent/components/intent-keyword-manager.tsx +8 -4
  165. package/blocks/intent/components/intent-screen.tsx +265 -0
  166. package/blocks/intent/components/keyword-detail.tsx +124 -0
  167. package/blocks/lifecycle/README.md +16 -0
  168. package/blocks/lifecycle/block.json +34 -7
  169. package/blocks/lifecycle/components/account-related.tsx +66 -0
  170. package/blocks/lifecycle/components/lifecycle-board.tsx +3 -1
  171. package/blocks/lifecycle/components/lifecycle-screen.tsx +149 -0
  172. package/blocks/lifecycle/lib/lifecycle.ts +1 -1
  173. package/blocks/lists/README.md +13 -0
  174. package/blocks/lists/block.json +39 -1
  175. package/blocks/lists/components/add-to-list-button.tsx +3 -2
  176. package/blocks/lists/components/list-picker.tsx +5 -1
  177. package/blocks/lists/components/list-table.tsx +11 -5
  178. package/blocks/lists/components/lists-screen.tsx +344 -0
  179. package/blocks/lists/components/suppression-manager.tsx +6 -2
  180. package/blocks/lists/components/suppressions-screen.tsx +255 -0
  181. package/blocks/mailboxes/README.md +17 -0
  182. package/blocks/mailboxes/block.json +65 -17
  183. package/blocks/mailboxes/components/connect-mailbox.tsx +23 -13
  184. package/blocks/mailboxes/components/domain-detail.tsx +142 -0
  185. package/blocks/mailboxes/components/domain-purchase.tsx +6 -3
  186. package/blocks/mailboxes/components/mailbox-detail.tsx +156 -0
  187. package/blocks/mailboxes/components/mailboxes-screen.tsx +223 -0
  188. package/blocks/mailboxes/components/warmup-health.tsx +4 -2
  189. package/blocks/mailboxes/lib/mailboxes-utils.ts +22 -1
  190. package/blocks/newsletter/README.md +13 -0
  191. package/blocks/newsletter/block.json +47 -23
  192. package/blocks/newsletter/components/issue-scheduler.tsx +2 -1
  193. package/blocks/newsletter/components/newsletter-screen.tsx +404 -0
  194. package/blocks/newsletter/components/subscriber-table.tsx +12 -6
  195. package/blocks/nurture/README.md +12 -0
  196. package/blocks/nurture/block.json +35 -13
  197. package/blocks/nurture/components/nurture-builder.tsx +3 -1
  198. package/blocks/nurture/components/nurture-enroll.tsx +6 -3
  199. package/blocks/nurture/components/nurture-form.tsx +23 -3
  200. package/blocks/nurture/components/nurture-screen.tsx +283 -0
  201. package/blocks/nurture/lib/nurture-types.ts +1 -1
  202. package/blocks/objects/README.md +17 -0
  203. package/blocks/objects/block.json +29 -16
  204. package/blocks/objects/components/object-not-found.tsx +3 -1
  205. package/blocks/objects/components/object-record-detail.tsx +2 -1
  206. package/blocks/objects/components/object-schema-editor.tsx +3 -1
  207. package/blocks/objects/components/object-table.tsx +13 -3
  208. package/blocks/objects/components/objects-screen.tsx +147 -0
  209. package/blocks/objects/lib/object-types.ts +1 -1
  210. package/blocks/pages/README.md +12 -0
  211. package/blocks/pages/block.json +35 -22
  212. package/blocks/pages/components/brand-kit-editor.tsx +5 -2
  213. package/blocks/pages/components/content-library.tsx +46 -11
  214. package/blocks/pages/components/page-list.tsx +6 -3
  215. package/blocks/pages/components/pages-screen.tsx +154 -0
  216. package/blocks/quotes/README.md +17 -0
  217. package/blocks/quotes/block.json +38 -9
  218. package/blocks/quotes/components/product-picker.tsx +3 -1
  219. package/blocks/quotes/components/quote-list.tsx +7 -3
  220. package/blocks/quotes/components/quote-related.tsx +123 -0
  221. package/blocks/quotes/components/quotes-screen.tsx +169 -0
  222. package/blocks/radar/README.md +10 -0
  223. package/blocks/radar/block.json +41 -1
  224. package/blocks/radar/components/competitor-detail.tsx +117 -0
  225. package/blocks/radar/components/competitor-tracker.tsx +3 -1
  226. package/blocks/radar/components/radar-report.tsx +4 -2
  227. package/blocks/radar/components/radar-screen.tsx +214 -0
  228. package/blocks/radar/components/report-detail.tsx +104 -0
  229. package/blocks/search/README.md +10 -0
  230. package/blocks/search/block.json +16 -1
  231. package/blocks/search/components/filter-builder.tsx +3 -3
  232. package/blocks/search/components/prospect-results.tsx +5 -3
  233. package/blocks/search/components/prospect-search-screen.tsx +235 -0
  234. package/blocks/search/components/saved-searches.tsx +4 -1
  235. package/blocks/search/hooks/use-filter-options.ts +20 -6
  236. package/blocks/search/lib/search-types.ts +2 -0
  237. package/blocks/sequencer/README.md +49 -9
  238. package/blocks/sequencer/block.json +99 -19
  239. package/blocks/sequencer/components/enroll-dialog.tsx +9 -3
  240. package/blocks/sequencer/components/sequence-builder.tsx +211 -46
  241. package/blocks/sequencer/components/sequence-detail.tsx +259 -0
  242. package/blocks/sequencer/components/sequence-enrollments.tsx +114 -0
  243. package/blocks/sequencer/components/sequence-list.tsx +33 -8
  244. package/blocks/sequencer/components/sequence-stats.tsx +3 -2
  245. package/blocks/sequencer/components/sequence-steps-panel.tsx +103 -0
  246. package/blocks/sequencer/components/sequences-screen.tsx +159 -0
  247. package/blocks/sequencer/components/step-editor.tsx +3 -1
  248. package/blocks/sequencer/lib/sequencer-utils.ts +128 -5
  249. package/blocks/sequencer/recipes/create-multichannel-sequence.ts +33 -5
  250. package/blocks/sequencer/recipes/launch-and-enroll.ts +19 -2
  251. package/blocks/social-ads/README.md +11 -0
  252. package/blocks/social-ads/block.json +101 -2
  253. package/blocks/social-ads/components/ad-campaign-list.tsx +9 -5
  254. package/blocks/social-ads/components/ads-screen.tsx +152 -0
  255. package/blocks/social-ads/components/audience-sync-detail.tsx +188 -0
  256. package/blocks/social-ads/components/audience-sync.tsx +11 -7
  257. package/blocks/social-ads/components/campaign-detail.tsx +133 -0
  258. package/blocks/social-ads/components/creative-detail.tsx +150 -0
  259. package/blocks/social-ads/components/creative-gallery.tsx +15 -5
  260. package/blocks/social-ads/components/post-composer.tsx +3 -1
  261. package/blocks/social-ads/components/post-detail.tsx +160 -0
  262. package/blocks/social-ads/components/social-post-list.tsx +11 -3
  263. package/blocks/social-ads/components/social-screen.tsx +160 -0
  264. package/blocks/visitors/README.md +10 -0
  265. package/blocks/visitors/block.json +25 -1
  266. package/blocks/visitors/components/snippet-install.tsx +3 -1
  267. package/blocks/visitors/components/visitor-company-card.tsx +2 -2
  268. package/blocks/visitors/components/visitor-detail.tsx +105 -0
  269. package/blocks/visitors/components/visitor-feed.tsx +11 -2
  270. package/blocks/visitors/components/visitors-screen.tsx +166 -0
  271. package/blocks/webchat/README.md +10 -0
  272. package/blocks/webchat/block.json +21 -7
  273. package/blocks/webchat/components/chat-widget-config.tsx +7 -4
  274. package/blocks/webchat/components/conversation-list.tsx +7 -3
  275. package/blocks/webchat/components/webchat-screen.tsx +245 -0
  276. package/blocks/workbench/README.md +11 -0
  277. package/blocks/workbench/block.json +48 -1
  278. package/blocks/workbench/components/column-recipe-editor.tsx +4 -2
  279. package/blocks/workbench/components/workbench-grid.tsx +9 -3
  280. package/blocks/workbench/components/workbench-row-detail.tsx +104 -0
  281. package/blocks/workbench/components/workbench-screen.tsx +192 -0
  282. package/blocks/workbench/components/workbench-sources.tsx +194 -0
  283. package/blocks/workflows/README.md +13 -0
  284. package/blocks/workflows/block.json +28 -9
  285. package/blocks/workflows/components/run-history.tsx +31 -9
  286. package/blocks/workflows/components/trigger-config.tsx +3 -1
  287. package/blocks/workflows/components/workflow-editor.tsx +3 -1
  288. package/blocks/workflows/components/workflow-list.tsx +13 -6
  289. package/blocks/workflows/components/workflows-screen.tsx +193 -0
  290. package/dist/cli.js +2785 -1637
  291. package/dist/errors.d.mts +34 -0
  292. package/dist/errors.d.ts +34 -0
  293. package/dist/errors.js +46 -0
  294. package/dist/errors.js.map +1 -0
  295. package/dist/errors.mjs +21 -0
  296. package/dist/errors.mjs.map +1 -0
  297. package/dist/index.browser.js +11 -5
  298. package/dist/index.browser.js.map +1 -1
  299. package/dist/index.browser.mjs +11 -5
  300. package/dist/index.browser.mjs.map +1 -1
  301. package/dist/index.d.mts +164 -25
  302. package/dist/index.d.ts +164 -25
  303. package/dist/index.js +11 -5
  304. package/dist/index.js.map +1 -1
  305. package/dist/index.mjs +11 -5
  306. package/dist/index.mjs.map +1 -1
  307. package/dist/react.browser.js +10 -4
  308. package/dist/react.browser.js.map +1 -1
  309. package/dist/react.browser.mjs +10 -4
  310. package/dist/react.browser.mjs.map +1 -1
  311. package/dist/react.d.mts +142 -5
  312. package/dist/react.d.ts +142 -5
  313. package/dist/react.js +10 -4
  314. package/dist/react.js.map +1 -1
  315. package/dist/react.mjs +10 -4
  316. package/dist/react.mjs.map +1 -1
  317. package/dist/types/blocks/add.d.ts +11 -4
  318. package/dist/types/blocks/brand.d.ts +113 -0
  319. package/dist/types/blocks/compose.d.ts +53 -0
  320. package/dist/types/blocks/create.d.ts +25 -8
  321. package/dist/types/blocks/doctor.d.ts +6 -1
  322. package/dist/types/blocks/flows.d.ts +20 -0
  323. package/dist/types/blocks/navfile.d.ts +35 -0
  324. package/dist/types/blocks/paths.d.ts +4 -0
  325. package/dist/types/blocks/prefixes.d.ts +37 -0
  326. package/dist/types/blocks/registry.d.ts +32 -0
  327. package/dist/types/blocks/screens.d.ts +53 -0
  328. package/dist/types/cli.d.ts +2 -0
  329. package/dist/types/errors.d.ts +33 -0
  330. package/dist/types/http.d.ts +2 -18
  331. package/dist/types/version.d.ts +2 -2
  332. package/docs/agents.md +15 -4
  333. package/docs/api/README.md +2 -2
  334. package/docs/api/by-path.md +1 -0
  335. package/docs/api/desk.d.ts +98 -2
  336. package/docs/api/desk.md +123 -1
  337. package/docs/api/inbox.d.ts +10 -2
  338. package/docs/api/inbox.md +10 -2
  339. package/docs/api/seo.d.ts +19 -1
  340. package/docs/api/seo.md +24 -1
  341. package/package.json +16 -2
  342. package/stacks/6sense.json +41 -16
  343. package/stacks/apollo/pages/companies.tsx.tmpl +50 -0
  344. package/stacks/apollo/pages/contacts.tsx.tmpl +117 -0
  345. package/stacks/apollo.json +118 -36
  346. package/stacks/calendly.json +60 -0
  347. package/stacks/clay/pages/companies.tsx.tmpl +15 -0
  348. package/stacks/clay/pages/contacts.tsx.tmpl +19 -0
  349. package/stacks/clay.json +59 -26
  350. package/stacks/gong.json +81 -35
  351. package/stacks/hootsuite.json +99 -0
  352. package/stacks/hubspot/pages/companies.tsx.tmpl +47 -0
  353. package/stacks/hubspot/pages/contacts.tsx.tmpl +111 -0
  354. package/stacks/hubspot/pages/deals.tsx.tmpl +11 -0
  355. package/stacks/hubspot/pages/inbox.tsx.tmpl +92 -0
  356. package/stacks/hubspot/pages/quotes.tsx.tmpl +11 -0
  357. package/stacks/hubspot.json +167 -66
  358. package/stacks/intercom.json +48 -20
  359. package/stacks/mailchimp.json +52 -33
  360. package/stacks/outreach/pages/contacts.tsx.tmpl +85 -0
  361. package/stacks/outreach.json +88 -25
  362. package/stacks/pipedrive/pages/companies.tsx.tmpl +47 -0
  363. package/stacks/pipedrive/pages/contacts.tsx.tmpl +47 -0
  364. package/stacks/pipedrive/pages/deals.tsx.tmpl +11 -0
  365. package/stacks/pipedrive/pages/inbox.tsx.tmpl +92 -0
  366. package/stacks/pipedrive/pages/quotes.tsx.tmpl +11 -0
  367. package/stacks/pipedrive.json +115 -0
  368. package/stacks/salesforce/pages/companies.tsx.tmpl +47 -0
  369. package/stacks/salesforce/pages/contacts.tsx.tmpl +47 -0
  370. package/stacks/salesforce/pages/deals.tsx.tmpl +11 -0
  371. package/stacks/salesforce/pages/quotes.tsx.tmpl +11 -0
  372. package/stacks/salesforce.json +81 -31
  373. package/stacks/stack.schema.json +6 -1
  374. package/stacks/zoominfo/pages/companies.tsx.tmpl +15 -0
  375. package/stacks/zoominfo/pages/contacts.tsx.tmpl +19 -0
  376. package/stacks/zoominfo.json +102 -0
  377. package/styles/styles.css +1 -1
  378. package/templates/next-app/README.md.tmpl +55 -8
  379. package/templates/next-app/app/globals.css.tmpl +105 -0
  380. package/templates/next-app/app/layout.tsx.tmpl +18 -4
  381. package/templates/next-app/components/app-shell.tsx.tmpl +248 -23
  382. package/templates/next-app/components/shell/connection-status.tsx.tmpl +109 -0
  383. package/templates/next-app/components/shell/nav-model.ts.tmpl +65 -0
  384. package/templates/next-app/components/shell/quick-jump.tsx.tmpl +131 -0
  385. package/templates/next-app/components/shell/theme-toggle.tsx.tmpl +40 -0
  386. package/templates/next-app/dot-gitignore.tmpl +2 -0
  387. package/templates/next-app/lib/nav.ts.tmpl +1 -1
  388. package/templates/next-app/package.json.tmpl +1 -1
@@ -26,8 +26,14 @@ import { EmptyState } from "@/g8/components/empty-state";
26
26
  import { ConfirmSpendDialog } from "@/g8/components/confirm-spend-dialog";
27
27
  import { blankConfig, payload, str } from "../lib/graph";
28
28
  import type { Rec, WorkflowRow } from "../lib/graph";
29
+ import { rowActivationProps } from "@/g8/hooks/use-row-activation";
30
+ import { RecordLink } from "@/g8/components/screen/record-link";
31
+ import { pluralWord } from "@/g8/lib/plural";
32
+ import { useBrand } from "@/g8/hooks/use-brand";
29
33
 
30
34
  export interface WorkflowListProps {
35
+ /** URL param the host screen reads for this record type. With it the name is a real link (Cmd-click opens it in a new tab); without it a plain button. */
36
+ linkParam?: string;
31
37
  /** Open a workflow in your WorkflowEditor route. */
32
38
  onOpen?: (actionId: string) => void;
33
39
  /** Called with `(actionId, executionId)` after a run starts, so you can show RunHistory. */
@@ -55,7 +61,8 @@ function planFacts(plan: Rec): { credits?: number; audience?: number; steps: num
55
61
  };
56
62
  }
57
63
 
58
- function RunPlan({ actionId, input, setInput }: { actionId: string; input: string; setInput: (v: string) => void }) {
64
+ export function RunPlan({ actionId, input, setInput }: { actionId: string; input: string; setInput: (v: string) => void }) {
65
+ const brand = useBrand();
59
66
  const plan = useG8Query((signal) => g8Post(`/workflows/${encodeURIComponent(actionId)}/plan`, {}, { signal }), [actionId]);
60
67
  const facts = planFacts(payload(plan.data));
61
68
  let valid = true;
@@ -64,9 +71,9 @@ function RunPlan({ actionId, input, setInput }: { actionId: string; input: strin
64
71
  <div className="space-y-2 text-left">
65
72
  {plan.loading ? <Skeleton className="h-4 w-48" /> : plan.error ? <p className="text-xs">The preview is unavailable; the run still works.</p> : (
66
73
  <p className="text-xs" data-testid="run-plan">
67
- {facts.steps} steps{facts.audience != null ? `, ${facts.audience.toLocaleString()} contacts in scope` : ""}
74
+ {facts.steps} {pluralWord(facts.steps, "step")}{facts.audience != null ? `, ${facts.audience.toLocaleString()} ${pluralWord(facts.audience, "contact")} in scope` : ""}
68
75
  {facts.credits != null ? `, about ${Math.round(facts.credits).toLocaleString()} credits (advisory)` : ""}
69
- {facts.approval ? ", waits for a human approval" : ""}{facts.external ? ", contacts people or systems outside graph8" : ""}.
76
+ {facts.approval ? ", waits for a human approval" : ""}{facts.external ? `, contacts people or systems outside ${brand.linkLabel}` : ""}.
70
77
  </p>
71
78
  )}
72
79
  <label className="block text-xs font-medium" htmlFor="run-input">Run input (JSON)</label>
@@ -86,7 +93,7 @@ function confirmCopy(p: Pending): { tier: "external" | "destructive"; title: str
86
93
  return { tier: "destructive", title: `Delete "${p.workflow.name}"`, label: "Delete", description: "The workflow and its trigger are removed. Past runs stay in history." };
87
94
  }
88
95
 
89
- export function WorkflowList({ onOpen, onRunStarted, className }: WorkflowListProps) {
96
+ export function WorkflowList({ linkParam, onOpen, onRunStarted, className }: WorkflowListProps) {
90
97
  const list = useG8Query((signal) => g8Get("/workflows", undefined, { signal }), []);
91
98
  const [name, setName] = useState("");
92
99
  const [pending, setPending] = useState<Pending | null>(null);
@@ -128,8 +135,8 @@ export function WorkflowList({ onOpen, onRunStarted, className }: WorkflowListPr
128
135
  <TableHeader><TableRow><TableHead>Name</TableHead><TableHead>Status</TableHead><TableHead>Category</TableHead><TableHead className="text-right">Actions</TableHead></TableRow></TableHeader>
129
136
  <TableBody>
130
137
  {rows.map((w) => (
131
- <TableRow key={w.action_id}>
132
- <TableCell><button type="button" className="font-medium hover:underline" onClick={() => onOpen?.(w.action_id)}>{w.name}</button>{w.description ? <div className="text-muted-foreground text-xs">{w.description}</div> : null}</TableCell>
138
+ <TableRow key={w.action_id} {...(onOpen ? rowActivationProps(() => onOpen(w.action_id)) : {})}>
139
+ <TableCell>{onOpen ? <RecordLink param={linkParam} id={w.action_id} onOpen={() => onOpen(w.action_id)}>{w.name}</RecordLink> : <span className="font-medium">{w.name}</span>}{w.description ? <div className="text-muted-foreground text-xs">{w.description}</div> : null}</TableCell>
133
140
  <TableCell>{w.enabled === false ? "Disabled" : "Enabled"}</TableCell>
134
141
  <TableCell>{w.category ?? ""}</TableCell>
135
142
  <TableCell className="space-x-1 text-right">
@@ -0,0 +1,193 @@
1
+ "use client";
2
+
3
+ /**
4
+ * WorkflowsScreen: the finished automations workspace. Two tabs.
5
+ * Workflows: stat strip (workflows, enabled, disabled, failed runs), search and status filter, the list with
6
+ * Run / Enable-Disable / Delete per row, and for the open workflow (deep link ?id=) a detail panel with
7
+ * Steps (WorkflowEditor), Trigger (TriggerConfig) and Runs (RunHistory for this workflow).
8
+ * Runs: every run across all workflows as a list; opening one (deep link ?run=) shows the full run (status, timing,
9
+ * who started it, error, input, output) with pause / resume / stop / restart.
10
+ * "New workflow" asks for a name, creates a manual-trigger workflow and opens it so steps can be added. Starting a
11
+ * run shows the plan preview (steps, audience, advisory credits) and the run input first, inside the confirm.
12
+ *
13
+ * Composes: WorkflowEditor, TriggerConfig, RunHistory, RunPlan (from WorkflowList).
14
+ *
15
+ * SDK operations of its own, in the order used:
16
+ * 1. GET /workflows (workflows.listWorkflows) read `{ actions, total }`
17
+ * 2. GET /workflows/executions?status_filter=failed&limit=1 (workflows.listWorkflowExecutions) read failed-run count
18
+ * 3. POST /workflows (workflows.createWorkflow) external -> ConfirmSpendDialog
19
+ * 4. POST /workflows/{id}/plan, then POST /workflows/{id}/execute { input_data } (plan read; execute external -> ConfirmSpendDialog)
20
+ * 5. PUT /workflows/{id} { enabled } (workflows.updateWorkflow) external -> ConfirmSpendDialog
21
+ * 6. DELETE /workflows/{id} (workflows.deleteWorkflow) destructive -> ConfirmSpendDialog
22
+ * Slot props: renderRowActions, renderDetailActions, extraDetailTabs, toolbarActions.
23
+ */
24
+ import { useEffect, useState, type ReactNode } from "react";
25
+ import { Plus, Workflow } from "lucide-react";
26
+ import { Button, Input, Skeleton } from "@graph8/sdk/ui";
27
+ import { ApiError } from "@/g8/components/api-error";
28
+ import { ConfirmSpendDialog } from "@/g8/components/confirm-spend-dialog";
29
+ import { EmptyState } from "@/g8/components/empty-state";
30
+ import { useG8Mutation } from "@/g8/hooks/use-g8-mutation";
31
+ import { useG8Query } from "@/g8/hooks/use-g8-query";
32
+ import { g8Delete, g8Get, g8Post, g8Put } from "@/g8/lib/g8-client";
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 { blankConfig, payload, str } from "../lib/graph";
41
+ import type { WorkflowRow } from "../lib/graph";
42
+ import { RunDetail, RunHistory } from "./run-history";
43
+ import { RunPlan } from "./workflow-list";
44
+ import { TriggerConfig } from "./trigger-config";
45
+ import { WorkflowEditor } from "./workflow-editor";
46
+
47
+ export interface WorkflowsScreenProps {
48
+ renderRowActions?: (workflow: WorkflowRow) => ReactNode;
49
+ renderDetailActions?: (workflow: WorkflowRow) => ReactNode;
50
+ extraDetailTabs?: Array<{ id: string; label: string; render: (workflow: WorkflowRow) => ReactNode }>;
51
+ toolbarActions?: ReactNode;
52
+ className?: string;
53
+ }
54
+
55
+ type Pending =
56
+ | { kind: "create"; name: string }
57
+ | { kind: "run"; workflow: WorkflowRow }
58
+ | { kind: "toggle"; workflow: WorkflowRow }
59
+ | { kind: "delete"; workflow: WorkflowRow };
60
+
61
+ const SCREEN_TABS = [{ id: "workflows", label: "Workflows" }, { id: "runs", label: "Runs" }];
62
+ const FILTERS = [{ id: "", label: "All" }, { id: "enabled", label: "Enabled" }, { id: "disabled", label: "Disabled" }];
63
+ const isOn = (w: WorkflowRow) => w.enabled !== false;
64
+
65
+ function copyFor(p: Pending): { tier: "external" | "destructive"; title: string; label: string; description?: string } {
66
+ if (p.kind === "create") return { tier: "external", title: `Create workflow "${p.name || "Untitled workflow"}"`, label: "Create", description: "A manual-trigger workflow with no steps yet. Add steps in the editor." };
67
+ if (p.kind === "run") return { tier: "external", title: `Run "${p.workflow.name}"`, label: "Run now" };
68
+ if (p.kind === "toggle") {
69
+ const on = isOn(p.workflow);
70
+ return { tier: "external", title: `${on ? "Disable" : "Enable"} "${p.workflow.name}"`, label: on ? "Disable" : "Enable", description: on ? "Its trigger stops firing." : "Its trigger starts firing and the workflow can act on real contacts." };
71
+ }
72
+ return { tier: "destructive", title: `Delete "${p.workflow.name}"`, label: "Delete", description: "The workflow and its trigger are removed. Past runs stay in history." };
73
+ }
74
+
75
+ export function WorkflowsScreen({ renderRowActions, renderDetailActions, extraDetailTabs, toolbarActions, className }: WorkflowsScreenProps) {
76
+ const [tab, setTab] = useUrlState("tab", "workflows");
77
+ const [selected, setSelected] = useUrlState("id", "");
78
+ const [search, setSearch] = useState("");
79
+ const [filter, setFilter] = useState("");
80
+ const [newName, setNewName] = useState("");
81
+ const [sheet, setSheet] = useState(false);
82
+ const [pending, setPending] = useState<Pending | null>(null);
83
+ const [input, setInput] = useState("{}");
84
+ const [run, setRun] = useUrlState("run", "");
85
+ const [view, setView] = useUrlState("view", "");
86
+ const closeWorkflow = () => { setSelected(""); setView(""); };
87
+ const closeRun = () => { setRun(""); setView(""); };
88
+ const expand = { expanded: view === "full", onExpandedChange: (e: boolean) => setView(e ? "full" : "") };
89
+ const [runsKey, setRunsKey] = useState(0);
90
+ const q = search.trim().toLowerCase();
91
+ useEffect(() => setInput("{}"), [pending]);
92
+
93
+ const list = useG8Query((signal) => g8Get("/workflows", undefined, { signal }), []);
94
+ const failed = useG8Query((signal) => g8Get("/workflows/executions", { status_filter: "failed", limit: 1 }, { signal }), []);
95
+ const all = (Array.isArray(payload(list.data).actions) ? payload(list.data).actions : []) as WorkflowRow[];
96
+ const failedTotal = payload(failed.data).total_count;
97
+ const rows = all.filter((w) => (!q || `${w.name} ${w.description ?? ""}`.toLowerCase().includes(q)) && (!filter || (filter === "enabled") === isOn(w)));
98
+ const open = all.find((w) => w.action_id === selected);
99
+
100
+ const act = useG8Mutation(async (p: Pending) => {
101
+ if (p.kind === "create") return g8Post("/workflows", { name: p.name || "Untitled workflow", description: "", config: blankConfig(p.name || "Untitled workflow") });
102
+ const base = `/workflows/${encodeURIComponent(p.workflow.action_id)}`;
103
+ if (p.kind === "run") return g8Post(`${base}/execute`, { input_data: JSON.parse(input || "{}") });
104
+ if (p.kind === "toggle") return g8Put(base, { enabled: !isOn(p.workflow) });
105
+ return g8Delete(base);
106
+ }, {
107
+ onSuccess: (res, p) => {
108
+ setPending(null);
109
+ if (p.kind === "create") { setNewName(""); setSheet(false); const id = str(payload(res).action_id); if (id) { setSelected(id); setTab("workflows"); } }
110
+ if (p.kind === "run") { setTab("runs"); setRun(str(payload(res).execution_id)); }
111
+ if (p.kind === "delete" && selected === p.workflow.action_id) setSelected("");
112
+ void list.refetch();
113
+ void failed.refetch();
114
+ },
115
+ });
116
+ let inputOk = true;
117
+ try { JSON.parse(input || "{}"); } catch { inputOk = false; }
118
+ const copy = pending ? copyFor(pending) : null;
119
+
120
+ const detail = open ? (
121
+ <DetailPanel title={open.name} subtitle={open.description ?? open.category ?? undefined} onClose={closeWorkflow} onExpand={() => setView("full")}
122
+ badges={<StatusPill tone={isOn(open) ? "positive" : "neutral"} dot>{isOn(open) ? "Enabled" : "Disabled"}</StatusPill>}
123
+ actions={<>
124
+ <Button size="sm" onClick={() => setPending({ kind: "run", workflow: open })}>Run</Button>
125
+ {renderDetailActions?.(open)}
126
+ </>}
127
+ tabs={[
128
+ { id: "steps", label: "Steps", content: <WorkflowEditor key={open.action_id} actionId={open.action_id} onSaved={() => void list.refetch()} /> },
129
+ { id: "trigger", label: "Trigger", content: <TriggerConfig key={open.action_id} actionId={open.action_id} onSaved={() => void list.refetch()} /> },
130
+ { id: "runs", label: "Runs", content: <RunHistory key={open.action_id} actionId={open.action_id} /> },
131
+ ...(extraDetailTabs ?? []).map((t) => ({ id: t.id, label: t.label, content: t.render(open) })),
132
+ ]} />
133
+ ) : selected && !list.loading ? <EmptyState title="Workflow not found" description="It may have been deleted." /> : null;
134
+
135
+ const listView = (
136
+ <div className="flex flex-col gap-3">
137
+ <Toolbar search={{ value: search, onChange: setSearch, placeholder: "Search workflows" }} actions={toolbarActions}
138
+ filters={<div role="group" aria-label="Status" className="flex gap-1">{FILTERS.map((f) => <Button key={f.id || "all"} size="sm" variant={filter === f.id ? "default" : "outline"} onClick={() => setFilter(f.id)}>{f.label}</Button>)}</div>} />
139
+ {list.error ? <ApiError error={list.error} title="Could not load workflows" onRetry={() => void list.refetch()} /> : null}
140
+ {act.error ? <ApiError error={act.error} title="That action failed" /> : null}
141
+ {list.loading && !list.data ? <div className="space-y-2" aria-busy="true">{[0, 1, 2].map((i) => <Skeleton key={i} className="h-14 w-full" />)}</div> : null}
142
+ <ul className="rounded-md border">
143
+ {rows.map((w) => (
144
+ <li key={w.action_id} className={`flex items-center gap-2 border-b px-3 py-2 ${w.action_id === selected ? "bg-accent" : ""}`}>
145
+ <button type="button" data-testid={`workflow-${w.action_id}`} onClick={() => setSelected(w.action_id)} className="min-w-0 flex-1 text-left">
146
+ <span className="block truncate text-sm font-medium">{w.name}</span>
147
+ <span className="block truncate text-xs text-muted-foreground">{w.description || w.category || "No description"}</span>
148
+ </button>
149
+ <StatusPill tone={isOn(w) ? "positive" : "neutral"} dot>{isOn(w) ? "Enabled" : "Disabled"}</StatusPill>
150
+ <Button size="sm" variant="outline" onClick={() => setPending({ kind: "run", workflow: w })}>Run</Button>
151
+ <Button size="sm" variant="ghost" onClick={() => setPending({ kind: "toggle", workflow: w })}>{isOn(w) ? "Disable" : "Enable"}</Button>
152
+ <Button size="sm" variant="ghost" aria-label={`Delete ${w.name}`} onClick={() => setPending({ kind: "delete", workflow: w })}>Delete</Button>
153
+ {renderRowActions?.(w)}
154
+ </li>
155
+ ))}
156
+ </ul>
157
+ {!list.loading && !list.error && rows.length === 0 ? (
158
+ <EmptyState title={all.length ? "No workflows match" : "No workflows yet"} description="A workflow runs steps automatically when its trigger fires or when you run it."
159
+ action={all.length ? undefined : <Button onClick={() => setSheet(true)}>New workflow</Button>} />
160
+ ) : null}
161
+ </div>
162
+ );
163
+
164
+ const current = tab === "runs" ? "runs" : "workflows";
165
+ return (
166
+ <ScreenLayout className={className} title="Workflows" description="Automations that run when something happens, or when you press Run."
167
+ icon={<Workflow className="size-5" />} tabs={SCREEN_TABS} activeTab={current} onTabChange={setTab}
168
+ actions={<Button onClick={() => setSheet(true)}><Plus className="mr-1 size-4" />New workflow</Button>}
169
+ stats={current === "workflows" ? [
170
+ { label: "Workflows", value: String(all.length) },
171
+ { label: "Enabled", value: String(all.filter(isOn).length), tone: "positive" },
172
+ { label: "Disabled", value: String(all.filter((w) => !isOn(w)).length) },
173
+ { label: "Failed runs", value: typeof failedTotal === "number" ? failedTotal.toLocaleString() : "-", tone: failedTotal ? "negative" : "neutral" },
174
+ ] : undefined}>
175
+ {current === "runs" ? (
176
+ <SplitView list={<RunHistory hideDetail selectedId={run || null} onSelectRun={(id) => setRun(id ?? "")} refreshKey={runsKey} nameFor={(id) => all.find((w) => w.action_id === id)?.name} />}
177
+ detailOpen={Boolean(run)} onCloseDetail={closeRun} {...expand} detailWidth="lg"
178
+ detail={run ? <DetailPanel title="Run" subtitle={run} onClose={closeRun} onExpand={() => setView("full")}
179
+ tabs={[{ id: "run", label: "Run", content: <RunDetail key={run} executionId={run} onChanged={() => setRunsKey((k) => k + 1)} /> }]} /> : null} />
180
+ ) : <SplitView list={listView} detail={detail} detailOpen={Boolean(selected)} onCloseDetail={closeWorkflow} {...expand} detailWidth="xl" />}
181
+
182
+ <FormSheet open={sheet} onOpenChange={setSheet} title="New workflow" description="Starts with a manual trigger and an end step. You add the steps next."
183
+ footer={<><Button variant="ghost" onClick={() => setSheet(false)}>Cancel</Button><Button onClick={() => setPending({ kind: "create", name: newName.trim() })}>Create</Button></>}>
184
+ <div className="flex flex-col gap-1"><label className="text-sm font-medium" htmlFor="wf-name">Name</label><Input id="wf-name" value={newName} onChange={(e) => setNewName(e.target.value)} placeholder="Workflow name" /></div>
185
+ </FormSheet>
186
+ {pending && copy ? (
187
+ <ConfirmSpendDialog open tier={copy.tier} title={copy.title} confirmLabel={copy.label} confirming={act.loading} affected={pending.kind === "delete" ? 1 : undefined}
188
+ description={pending.kind === "run" ? <RunPlan actionId={pending.workflow.action_id} input={input} setInput={setInput} /> : copy.description}
189
+ onConfirm={() => { if (pending.kind !== "run" || inputOk) void act.mutate(pending); }} onCancel={() => setPending(null)} />
190
+ ) : null}
191
+ </ScreenLayout>
192
+ );
193
+ }