@graph8/sdk 0.362.0 → 0.373.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -10
- package/blocks/_foundation/README.md +78 -1
- package/blocks/_foundation/block.json +123 -6
- package/blocks/_foundation/components/api-error.tsx +9 -7
- package/blocks/_foundation/components/brand-provider.tsx +23 -0
- package/blocks/_foundation/components/confirm-spend-dialog.tsx +15 -8
- package/blocks/_foundation/components/confirmed-action.tsx +90 -0
- package/blocks/_foundation/components/connect-graph8.tsx +280 -0
- package/blocks/_foundation/components/empty-state.tsx +5 -2
- package/blocks/_foundation/components/list-select.tsx +112 -0
- package/blocks/_foundation/components/paging-notices.tsx +55 -0
- package/blocks/_foundation/components/screen/detail-panel.tsx +2 -1
- package/blocks/_foundation/components/screen/filter-controls.tsx +92 -0
- package/blocks/_foundation/components/screen/index.ts +2 -0
- package/blocks/_foundation/components/screen/record-link.tsx +76 -0
- package/blocks/_foundation/components/screen/split-view.tsx +1 -1
- package/blocks/_foundation/components/screen/time-series-chart-recharts.tsx +65 -0
- package/blocks/_foundation/components/screen/time-series-chart.tsx +15 -97
- package/blocks/_foundation/components/screen/time-series-format.ts +57 -0
- package/blocks/_foundation/hooks/use-all-pages.ts +54 -0
- package/blocks/_foundation/hooks/use-brand.ts +52 -0
- package/blocks/_foundation/hooks/use-g8-mutation.ts +23 -0
- package/blocks/_foundation/hooks/use-g8-query.ts +127 -1
- package/blocks/_foundation/hooks/use-load-more-list.ts +61 -0
- package/blocks/_foundation/hooks/use-paginated.ts +120 -0
- package/blocks/_foundation/hooks/use-row-activation.ts +57 -0
- package/blocks/_foundation/hooks/use-url-filters.ts +93 -0
- package/blocks/_foundation/lib/g8-cache.ts +454 -0
- package/blocks/_foundation/lib/g8-client.ts +1 -1
- package/blocks/_foundation/lib/paging.ts +57 -0
- package/blocks/_foundation/lib/plural.ts +23 -0
- package/blocks/_foundation/lib/use-debounced-value.ts +13 -0
- package/blocks/_foundation/server/connect-route.ts +15 -0
- package/blocks/_foundation/server/connect.ts +127 -0
- package/blocks/_foundation/server/local-key.ts +70 -0
- package/blocks/_foundation/server/proxy.ts +103 -3
- package/blocks/_foundation/server/route.ts +16 -4
- package/blocks/agents/README.md +93 -2
- package/blocks/agents/block.json +343 -2
- package/blocks/agents/components/agent-activity.tsx +112 -0
- package/blocks/agents/components/agent-approvals.tsx +135 -0
- package/blocks/agents/components/agent-builder.tsx +29 -10
- package/blocks/agents/components/agent-conversations.tsx +143 -0
- package/blocks/agents/components/agent-knowledge-panel.tsx +4 -3
- package/blocks/agents/components/agent-operators.tsx +164 -0
- package/blocks/agents/components/agent-run-detail.tsx +119 -0
- package/blocks/agents/components/agent-runs.tsx +19 -10
- package/blocks/agents/components/agent-skills-panel.tsx +7 -7
- package/blocks/agents/components/agent-test-history.tsx +121 -0
- package/blocks/agents/components/agents-screen.tsx +226 -0
- package/blocks/agents/components/assistant-sessions.tsx +150 -0
- package/blocks/agents/components/duplicate-agent-button.tsx +42 -0
- package/blocks/agents/components/from-template-button.tsx +65 -0
- package/blocks/agents/components/knowledge-browser.tsx +107 -0
- package/blocks/agents/components/knowledge-detail.tsx +156 -0
- package/blocks/agents/components/knowledge-form.tsx +69 -0
- package/blocks/agents/components/name-dialog.tsx +32 -0
- package/blocks/agents/components/receptionist-button.tsx +46 -0
- package/blocks/agents/components/save-as-template-button.tsx +32 -0
- package/blocks/agents/components/skill-editor.tsx +147 -0
- package/blocks/agents/components/skill-library.tsx +111 -0
- package/blocks/agents/lib/agent-types.ts +7 -1
- package/blocks/agents/lib/facts.tsx +13 -0
- package/blocks/agents/lib/knowledge-utils.ts +49 -0
- package/blocks/agents/lib/load-more.tsx +141 -0
- package/blocks/agents/lib/skill-utils.ts +91 -0
- package/blocks/agents/recipes/create-agent-and-attach-skill.ts +1 -1
- package/blocks/analytics/README.md +13 -0
- package/blocks/analytics/block.json +45 -1
- package/blocks/analytics/components/analytics-screen.tsx +222 -0
- package/blocks/analytics/components/kpi-tiles.tsx +1 -1
- package/blocks/analytics/components/leaderboard.tsx +14 -7
- package/blocks/analytics/components/report-builder.tsx +38 -11
- package/blocks/analytics/components/report-detail.tsx +84 -0
- package/blocks/analytics/components/trend-chart.tsx +62 -0
- package/blocks/appointments/README.md +6 -0
- package/blocks/appointments/block.json +33 -2
- package/blocks/appointments/components/availability-editor.tsx +17 -5
- package/blocks/appointments/components/booking-page.tsx +2 -2
- package/blocks/appointments/components/event-type-editor.tsx +2 -1
- package/blocks/appointments/components/event-type-related.tsx +4 -2
- package/blocks/appointments/components/meeting-contact-links.tsx +49 -0
- package/blocks/appointments/components/meeting-detail.tsx +2 -2
- package/blocks/appointments/components/meeting-list.tsx +38 -18
- package/blocks/appointments/components/meetings-screen.tsx +7 -4
- package/blocks/appointments/components/record-meetings-tab.tsx +92 -0
- package/blocks/appointments/components/scheduling-screen.tsx +2 -1
- package/blocks/block.schema.json +18 -0
- package/blocks/block.types.ts +17 -0
- package/blocks/campaigns/README.md +41 -11
- package/blocks/campaigns/block.json +105 -42
- package/blocks/campaigns/components/campaign-assets.tsx +17 -6
- package/blocks/campaigns/components/campaign-launch-step.tsx +114 -26
- package/blocks/campaigns/components/campaign-list.tsx +7 -3
- package/blocks/campaigns/components/campaign-metrics.tsx +1 -1
- package/blocks/campaigns/components/campaign-wizard.tsx +52 -14
- package/blocks/campaigns/components/campaigns-screen.tsx +267 -0
- package/blocks/campaigns/components/icp-detail.tsx +163 -0
- package/blocks/campaigns/components/icp-editor.tsx +22 -17
- package/blocks/campaigns/components/persona-detail.tsx +181 -0
- package/blocks/campaigns/components/persona-editor.tsx +19 -11
- package/blocks/campaigns/lib/campaigns-utils.ts +138 -5
- package/blocks/campaigns/recipes/attach-audience-and-launch.ts +16 -3
- package/blocks/campaigns/recipes/generate-ideas-and-create-campaign.ts +8 -4
- package/blocks/coach/README.md +10 -0
- package/blocks/coach/block.json +16 -1
- package/blocks/coach/components/call-scorecard.tsx +7 -7
- package/blocks/coach/components/coach-screen.tsx +222 -0
- package/blocks/company-intelligence/README.md +132 -0
- package/blocks/company-intelligence/block.json +318 -0
- package/blocks/company-intelligence/components/company-intelligence-screen.tsx +114 -0
- package/blocks/company-intelligence/components/company-intelligence-tab.tsx +88 -0
- package/blocks/company-intelligence/components/company-profile.tsx +68 -0
- package/blocks/company-intelligence/components/intelligence-sources.tsx +63 -0
- package/blocks/company-intelligence/components/report-detail.tsx +189 -0
- package/blocks/company-intelligence/components/research-reports.tsx +136 -0
- package/blocks/company-intelligence/components/research-run.tsx +161 -0
- package/blocks/company-intelligence/components/source-detail.tsx +117 -0
- package/blocks/company-intelligence/components/source-view.tsx +274 -0
- package/blocks/company-intelligence/components/wiki-document-detail.tsx +116 -0
- package/blocks/company-intelligence/components/wiki-documents.tsx +66 -0
- package/blocks/company-intelligence/hooks/use-intelligence.ts +173 -0
- package/blocks/company-intelligence/lib/intelligence-types.ts +230 -0
- package/blocks/company-intelligence/lib/safe-markdown.tsx +150 -0
- package/blocks/company-intelligence/recipes/read-competitors-and-news.ts +33 -0
- package/blocks/company-intelligence/recipes/research-your-website.ts +43 -0
- package/blocks/company-intelligence/recipes/write-the-research-reports.ts +54 -0
- package/blocks/copilot/README.md +13 -0
- package/blocks/copilot/block.json +14 -1
- package/blocks/copilot/components/copilot-memory.tsx +6 -2
- package/blocks/copilot/components/copilot-panel.tsx +14 -5
- package/blocks/copilot/components/copilot-screen.tsx +148 -0
- package/blocks/copilot/components/copilot-team-chat.tsx +13 -6
- package/blocks/crm/README.md +34 -0
- package/blocks/crm/block.json +107 -2
- package/blocks/crm/components/companies-screen.tsx +359 -0
- package/blocks/crm/components/company-detail.tsx +10 -8
- package/blocks/crm/components/company-table.tsx +11 -4
- package/blocks/crm/components/contact-detail.tsx +10 -7
- package/blocks/crm/components/contact-lookup-link.tsx +44 -0
- package/blocks/crm/components/contact-table.tsx +10 -3
- package/blocks/crm/components/contacts-screen.tsx +377 -0
- package/blocks/crm/components/dedupe-review.tsx +13 -6
- package/blocks/crm/components/import-wizard.tsx +7 -9
- package/blocks/crm/components/list-select.tsx +20 -0
- package/blocks/crm/components/notes-panel.tsx +4 -4
- package/blocks/crm/components/record-engagement-tab.tsx +103 -0
- package/blocks/crm/components/record-form.tsx +6 -4
- package/blocks/crm/components/task-list.tsx +4 -4
- package/blocks/crm/components/tasks-screen.tsx +399 -0
- package/blocks/crm/hooks/use-all-lists.ts +18 -0
- package/blocks/crm/hooks/use-custom-fields.ts +6 -1
- package/blocks/crm/hooks/use-page-query.ts +9 -1
- package/blocks/crm/lib/crm-types.ts +26 -2
- package/blocks/crm/lib/read-lists.ts +16 -0
- package/blocks/crm/lib/screen-parts.tsx +105 -0
- package/blocks/deals/README.md +24 -6
- package/blocks/deals/block.json +160 -5
- package/blocks/deals/components/close-deal-dialog.tsx +169 -0
- package/blocks/deals/components/deal-contacts-editor.tsx +134 -0
- package/blocks/deals/components/deal-detail.tsx +25 -13
- package/blocks/deals/components/deal-filters.tsx +65 -0
- package/blocks/deals/components/deal-line-items.tsx +120 -0
- package/blocks/deals/components/deal-notes-tab.tsx +97 -0
- package/blocks/deals/components/deal-related.tsx +31 -10
- package/blocks/deals/components/deal-tasks-tab.tsx +88 -0
- package/blocks/deals/components/deals-screen.tsx +66 -26
- package/blocks/deals/components/forecast-view.tsx +4 -4
- package/blocks/deals/components/pipeline-board.tsx +8 -6
- package/blocks/deals/components/pipeline-editor.tsx +132 -0
- package/blocks/deals/components/record-deals-tab.tsx +62 -0
- package/blocks/deals/components/stage-editor.tsx +5 -5
- package/blocks/deals/hooks/use-pipeline-deals.ts +21 -4
- package/blocks/deals/hooks/use-pipelines.ts +1 -1
- package/blocks/deals/lib/deal-extras.ts +156 -0
- package/blocks/dialer/README.md +45 -4
- package/blocks/dialer/block.json +84 -3
- package/blocks/dialer/components/call-contact-button.tsx +269 -0
- package/blocks/dialer/components/call-log-screen.tsx +208 -0
- package/blocks/dialer/components/call-log.tsx +23 -7
- package/blocks/dialer/components/call-queue.tsx +4 -4
- package/blocks/dialer/components/dialer-screen.tsx +361 -0
- package/blocks/dialer/components/dialer-session-detail.tsx +153 -0
- package/blocks/dialer/components/disposition-panel.tsx +1 -1
- package/blocks/dialer/components/live-calls-table.tsx +7 -3
- package/blocks/dialer/components/record-calls-tab.tsx +101 -0
- package/blocks/dialer/components/session-start-form.tsx +61 -12
- package/blocks/dialer/components/softphone.tsx +4 -2
- package/blocks/enrichment/README.md +29 -7
- package/blocks/enrichment/block.json +49 -9
- package/blocks/enrichment/components/bulk-enrich-panel.tsx +83 -29
- package/blocks/enrichment/components/email-verify-badge.tsx +31 -11
- package/blocks/enrichment/components/enrich-button.tsx +32 -9
- package/blocks/enrichment/components/enrichment-job-detail.tsx +78 -0
- package/blocks/enrichment/components/enrichment-screen.tsx +341 -0
- package/blocks/enrichment/components/waterfall-config.tsx +66 -17
- package/blocks/enrichment/lib/enrichment-types.ts +39 -0
- package/blocks/enrichment/recipes/bulk-enrich-and-poll.ts +15 -4
- package/blocks/enrichment/recipes/waterfall-pipeline.ts +3 -2
- package/blocks/forms/README.md +8 -0
- package/blocks/forms/block.json +139 -18
- package/blocks/forms/components/form-activity.tsx +71 -0
- package/blocks/forms/components/form-backfill.tsx +108 -0
- package/blocks/forms/components/form-builder.tsx +4 -2
- package/blocks/forms/components/form-embed.tsx +4 -2
- package/blocks/forms/components/form-groups.tsx +151 -0
- package/blocks/forms/components/form-mapping-editor.tsx +6 -9
- package/blocks/forms/components/form-route-history.tsx +72 -0
- package/blocks/forms/components/form-saved-views.tsx +81 -0
- package/blocks/forms/components/forms-screen.tsx +56 -19
- package/blocks/forms/components/more-rows.tsx +30 -0
- package/blocks/forms/components/submissions-export.tsx +67 -0
- package/blocks/forms/components/submissions-table.tsx +17 -6
- package/blocks/forms/lib/forms-extra.ts +67 -0
- package/blocks/inbox/README.md +32 -3
- package/blocks/inbox/block.json +29 -2
- package/blocks/inbox/components/inbox-list.tsx +7 -3
- package/blocks/inbox/components/inbox-screen.tsx +294 -27
- package/blocks/inbox/components/record-conversations-tab.tsx +154 -0
- package/blocks/inbox/components/reply-composer.tsx +65 -9
- package/blocks/inbox/components/tag-and-assign.tsx +4 -2
- package/blocks/inbox/components/thread-badge.tsx +2 -2
- package/blocks/inbox/components/thread-view.tsx +1 -1
- package/blocks/inbox/hooks/use-inbox-thread.ts +1 -1
- package/blocks/inbox/hooks/use-inbox-threads.ts +1 -0
- package/blocks/inbox/lib/inbox-types.ts +47 -1
- package/blocks/inbox/recipes/01-triage-and-reply.ts +12 -2
- package/blocks/integrations/README.md +63 -1
- package/blocks/integrations/block.json +234 -15
- package/blocks/integrations/components/ad-accounts.tsx +82 -0
- package/blocks/integrations/components/connection-health.tsx +59 -0
- package/blocks/integrations/components/crm-detail.tsx +119 -0
- package/blocks/integrations/components/crm-records.tsx +103 -0
- package/blocks/integrations/components/field-mappings.tsx +61 -0
- package/blocks/integrations/components/integration-list.tsx +13 -8
- package/blocks/integrations/components/integrations-screen.tsx +152 -0
- package/blocks/integrations/components/migration-panel.tsx +133 -0
- package/blocks/integrations/components/sugarcrm-connect.tsx +95 -0
- package/blocks/integrations/components/sync-status.tsx +11 -9
- package/blocks/integrations/components/sync-triggers.tsx +134 -0
- package/blocks/integrations/components/webhook-detail.tsx +179 -0
- package/blocks/integrations/components/webhook-manager.tsx +43 -25
- package/blocks/integrations/components/workspace-tools.tsx +127 -0
- package/blocks/integrations/lib/crm-utils.ts +39 -0
- package/blocks/integrations/lib/facts.tsx +13 -0
- package/blocks/integrations/lib/integrations-utils.ts +11 -1
- package/blocks/integrations/lib/load-more.tsx +141 -0
- package/blocks/intent/README.md +14 -0
- package/blocks/intent/block.json +27 -1
- package/blocks/intent/components/account-intent-score.tsx +5 -5
- package/blocks/intent/components/intent-feed.tsx +13 -10
- package/blocks/intent/components/intent-keyword-manager.tsx +16 -12
- package/blocks/intent/components/intent-screen.tsx +265 -0
- package/blocks/intent/components/keyword-detail.tsx +124 -0
- package/blocks/intent/lib/intent-utils.ts +4 -4
- package/blocks/lifecycle/block.json +13 -8
- package/blocks/lifecycle/components/account-related.tsx +8 -1
- package/blocks/lifecycle/components/churn-list.tsx +5 -2
- package/blocks/lifecycle/components/customer-table.tsx +1 -1
- package/blocks/lifecycle/components/lifecycle-board.tsx +3 -1
- package/blocks/lifecycle/components/lifecycle-screen.tsx +3 -1
- package/blocks/lifecycle/lib/lifecycle.ts +1 -1
- package/blocks/lists/README.md +20 -1
- package/blocks/lists/block.json +69 -3
- package/blocks/lists/components/add-company-people-to-list-button.tsx +73 -0
- package/blocks/lists/components/add-to-list-button.tsx +20 -9
- package/blocks/lists/components/list-picker.tsx +17 -3
- package/blocks/lists/components/list-table.tsx +12 -6
- package/blocks/lists/components/lists-screen.tsx +346 -0
- package/blocks/lists/components/record-lists-tab.tsx +99 -0
- package/blocks/lists/components/suppression-manager.tsx +33 -8
- package/blocks/lists/components/suppressions-screen.tsx +264 -0
- package/blocks/mailboxes/README.md +17 -0
- package/blocks/mailboxes/block.json +69 -17
- package/blocks/mailboxes/components/connect-mailbox.tsx +32 -21
- package/blocks/mailboxes/components/domain-detail.tsx +148 -0
- package/blocks/mailboxes/components/domain-purchase.tsx +20 -14
- package/blocks/mailboxes/components/mailbox-detail.tsx +157 -0
- package/blocks/mailboxes/components/mailbox-list.tsx +8 -3
- package/blocks/mailboxes/components/mailboxes-screen.tsx +228 -0
- package/blocks/mailboxes/components/warmup-health.tsx +24 -22
- package/blocks/mailboxes/lib/mailboxes-utils.ts +26 -5
- package/blocks/mailboxes/lib/use-provider-domains.ts +23 -0
- package/blocks/newsletter/README.md +12 -0
- package/blocks/newsletter/block.json +157 -24
- package/blocks/newsletter/components/issue-scheduler.tsx +4 -3
- package/blocks/newsletter/components/issue-versions.tsx +93 -0
- package/blocks/newsletter/components/more-rows.tsx +30 -0
- package/blocks/newsletter/components/newsletter-editor.tsx +1 -1
- package/blocks/newsletter/components/newsletter-list-syncs.tsx +121 -0
- package/blocks/newsletter/components/newsletter-screen.tsx +39 -14
- package/blocks/newsletter/components/newsletter-settings.tsx +211 -0
- package/blocks/newsletter/components/newsletter-stats.tsx +2 -2
- package/blocks/newsletter/components/newsletter-templates.tsx +133 -0
- package/blocks/newsletter/components/subscriber-table.tsx +5 -7
- package/blocks/newsletter/components/subscriber-timeline.tsx +65 -0
- package/blocks/newsletter/lib/newsletter-extra.ts +60 -0
- package/blocks/nurture/block.json +28 -14
- package/blocks/nurture/components/nurture-builder.tsx +13 -3
- package/blocks/nurture/components/nurture-enroll.tsx +12 -10
- package/blocks/nurture/components/nurture-form.tsx +27 -10
- package/blocks/nurture/components/nurture-screen.tsx +26 -11
- package/blocks/nurture/components/nurture-stats.tsx +5 -4
- package/blocks/nurture/lib/nurture-types.ts +1 -1
- package/blocks/objects/README.md +18 -1
- package/blocks/objects/block.json +42 -21
- package/blocks/objects/components/attribute-field-input.tsx +14 -1
- package/blocks/objects/components/object-not-found.tsx +3 -1
- package/blocks/objects/components/object-record-detail.tsx +10 -2
- package/blocks/objects/components/object-schema-editor.tsx +4 -2
- package/blocks/objects/components/object-table.tsx +13 -3
- package/blocks/objects/components/objects-screen.tsx +147 -0
- package/blocks/objects/components/record-roles-panel.tsx +15 -5
- package/blocks/objects/lib/object-types.ts +1 -1
- package/blocks/pages/README.md +14 -0
- package/blocks/pages/block.json +140 -23
- package/blocks/pages/components/brand-kit-editor.tsx +5 -2
- package/blocks/pages/components/content-library.tsx +9 -4
- package/blocks/pages/components/more-rows.tsx +30 -0
- package/blocks/pages/components/page-ai-tools.tsx +196 -0
- package/blocks/pages/components/page-analytics.tsx +176 -0
- package/blocks/pages/components/page-clone.tsx +99 -0
- package/blocks/pages/components/page-domains.tsx +167 -0
- package/blocks/pages/components/page-editor.tsx +1 -1
- package/blocks/pages/components/page-generation-status.tsx +48 -0
- package/blocks/pages/components/page-list.tsx +2 -1
- package/blocks/pages/components/page-tracking.tsx +137 -0
- package/blocks/pages/components/pages-screen.tsx +57 -16
- package/blocks/pages/components/seo-report.tsx +6 -1
- package/blocks/pages/lib/studio.ts +7 -0
- package/blocks/phone-numbers/README.md +74 -0
- package/blocks/phone-numbers/block.json +262 -0
- package/blocks/phone-numbers/components/a2p-registration.tsx +230 -0
- package/blocks/phone-numbers/components/assign-number.tsx +104 -0
- package/blocks/phone-numbers/components/number-search.tsx +239 -0
- package/blocks/phone-numbers/components/number-settings.tsx +134 -0
- package/blocks/phone-numbers/components/number-usage.tsx +97 -0
- package/blocks/phone-numbers/components/phone-number-detail.tsx +84 -0
- package/blocks/phone-numbers/components/phone-number-list.tsx +110 -0
- package/blocks/phone-numbers/components/phone-numbers-screen.tsx +201 -0
- package/blocks/phone-numbers/components/register-owned-number.tsx +98 -0
- package/blocks/phone-numbers/components/release-number.tsx +126 -0
- package/blocks/phone-numbers/hooks/use-phone-numbers.ts +58 -0
- package/blocks/phone-numbers/lib/phone-numbers-utils.ts +202 -0
- package/blocks/phone-numbers/recipes/01-search-and-buy-number.ts +49 -0
- package/blocks/phone-numbers/recipes/02-assign-number-to-rep.ts +25 -0
- package/blocks/phone-numbers/recipes/03-audit-numbers.ts +36 -0
- package/blocks/phone-numbers/recipes/04-register-text-messaging.ts +39 -0
- package/blocks/pickers/README.md +23 -0
- package/blocks/pickers/block.json +103 -0
- package/blocks/pickers/components/company-picker.tsx +90 -0
- package/blocks/pickers/components/contact-picker.tsx +131 -0
- package/blocks/pickers/components/member-picker.tsx +99 -0
- package/blocks/pickers/components/search-picker.tsx +98 -0
- package/blocks/pickers/hooks/use-current-member.ts +104 -0
- package/blocks/pickers/hooks/use-picker-pages.ts +73 -0
- package/blocks/pickers/lib/use-debounced.ts +13 -0
- package/blocks/quotes/README.md +13 -0
- package/blocks/quotes/block.json +65 -13
- package/blocks/quotes/components/create-quote-from-deal.tsx +48 -0
- package/blocks/quotes/components/product-picker.tsx +3 -1
- package/blocks/quotes/components/quote-builder.tsx +1 -1
- package/blocks/quotes/components/quote-lifecycle-actions.tsx +146 -0
- package/blocks/quotes/components/quote-list.tsx +5 -3
- package/blocks/quotes/components/quote-related.tsx +8 -4
- package/blocks/quotes/components/quote-viewer.tsx +7 -2
- package/blocks/quotes/components/record-quotes-tab.tsx +90 -0
- package/blocks/radar/README.md +10 -0
- package/blocks/radar/block.json +41 -1
- package/blocks/radar/components/competitor-battle-card.tsx +1 -1
- package/blocks/radar/components/competitor-detail.tsx +117 -0
- package/blocks/radar/components/competitor-tracker.tsx +3 -1
- package/blocks/radar/components/radar-overview.tsx +4 -4
- package/blocks/radar/components/radar-report.tsx +4 -2
- package/blocks/radar/components/radar-screen.tsx +214 -0
- package/blocks/radar/components/report-detail.tsx +104 -0
- package/blocks/search/README.md +10 -0
- package/blocks/search/block.json +16 -1
- package/blocks/search/components/filter-builder.tsx +3 -3
- package/blocks/search/components/prospect-results.tsx +5 -3
- package/blocks/search/components/prospect-search-screen.tsx +235 -0
- package/blocks/search/components/saved-searches.tsx +4 -1
- package/blocks/search/hooks/use-filter-options.ts +20 -6
- package/blocks/search/lib/search-types.ts +2 -0
- package/blocks/sequencer/README.md +55 -9
- package/blocks/sequencer/block.json +126 -19
- package/blocks/sequencer/components/add-to-sequence-button.tsx +82 -0
- package/blocks/sequencer/components/enroll-dialog.tsx +11 -5
- package/blocks/sequencer/components/record-sequences-tab.tsx +126 -0
- package/blocks/sequencer/components/sequence-builder.tsx +224 -60
- package/blocks/sequencer/components/sequence-detail.tsx +261 -0
- package/blocks/sequencer/components/sequence-enrollments.tsx +116 -0
- package/blocks/sequencer/components/sequence-list.tsx +34 -9
- package/blocks/sequencer/components/sequence-stats.tsx +11 -10
- package/blocks/sequencer/components/sequence-steps-panel.tsx +103 -0
- package/blocks/sequencer/components/sequences-screen.tsx +162 -0
- package/blocks/sequencer/components/step-editor.tsx +14 -12
- package/blocks/sequencer/lib/sequencer-utils.ts +133 -10
- package/blocks/sequencer/recipes/create-multichannel-sequence.ts +33 -5
- package/blocks/sequencer/recipes/launch-and-enroll.ts +19 -2
- package/blocks/social-ads/README.md +19 -0
- package/blocks/social-ads/block.json +233 -1
- package/blocks/social-ads/components/ad-campaign-list.tsx +9 -5
- package/blocks/social-ads/components/ads-screen.tsx +152 -0
- package/blocks/social-ads/components/audience-sync-detail.tsx +194 -0
- package/blocks/social-ads/components/audience-sync.tsx +17 -9
- package/blocks/social-ads/components/campaign-ads.tsx +166 -0
- package/blocks/social-ads/components/campaign-detail.tsx +138 -0
- package/blocks/social-ads/components/campaign-editor.tsx +134 -0
- package/blocks/social-ads/components/creative-concepts.tsx +74 -0
- package/blocks/social-ads/components/creative-detail.tsx +155 -0
- package/blocks/social-ads/components/creative-gallery.tsx +35 -7
- package/blocks/social-ads/components/creative-revisions.tsx +57 -0
- package/blocks/social-ads/components/creative-tools.tsx +176 -0
- package/blocks/social-ads/components/post-composer.tsx +7 -3
- package/blocks/social-ads/components/post-detail.tsx +163 -0
- package/blocks/social-ads/components/social-ideas.tsx +64 -0
- package/blocks/social-ads/components/social-performance.tsx +80 -0
- package/blocks/social-ads/components/social-post-list.tsx +11 -3
- package/blocks/social-ads/components/social-screen.tsx +187 -0
- package/blocks/social-ads/lib/ads-extra.ts +67 -0
- package/blocks/surveys/README.md +91 -0
- package/blocks/surveys/block.json +299 -0
- package/blocks/surveys/components/account-nps.tsx +69 -0
- package/blocks/surveys/components/contact-survey-history.tsx +52 -0
- package/blocks/surveys/components/org-summary.tsx +82 -0
- package/blocks/surveys/components/sending-domains.tsx +113 -0
- package/blocks/surveys/components/survey-form.tsx +126 -0
- package/blocks/surveys/components/survey-responses.tsx +145 -0
- package/blocks/surveys/components/survey-results.tsx +72 -0
- package/blocks/surveys/components/survey-send-history.tsx +58 -0
- package/blocks/surveys/components/survey-send.tsx +162 -0
- package/blocks/surveys/components/survey-triggers.tsx +166 -0
- package/blocks/surveys/components/surveys-screen.tsx +234 -0
- package/blocks/surveys/lib/surveys-types.ts +228 -0
- package/blocks/surveys/recipes/create-an-nps-survey.ts +22 -0
- package/blocks/surveys/recipes/send-a-survey-and-follow-it.ts +27 -0
- package/blocks/surveys/recipes/survey-score-report.ts +27 -0
- package/blocks/visitors/README.md +10 -0
- package/blocks/visitors/block.json +25 -1
- package/blocks/visitors/components/snippet-install.tsx +21 -10
- package/blocks/visitors/components/traffic-chart.tsx +4 -4
- package/blocks/visitors/components/visitor-company-card.tsx +26 -16
- package/blocks/visitors/components/visitor-detail.tsx +105 -0
- package/blocks/visitors/components/visitor-feed.tsx +16 -7
- package/blocks/visitors/components/visitors-screen.tsx +166 -0
- package/blocks/webchat/README.md +10 -0
- package/blocks/webchat/block.json +21 -7
- package/blocks/webchat/components/chat-widget-config.tsx +8 -5
- package/blocks/webchat/components/conversation-list.tsx +8 -4
- package/blocks/webchat/components/webchat-screen.tsx +245 -0
- package/blocks/workbench/README.md +11 -0
- package/blocks/workbench/block.json +48 -1
- package/blocks/workbench/components/column-recipe-editor.tsx +5 -3
- package/blocks/workbench/components/run-progress.tsx +1 -1
- package/blocks/workbench/components/workbench-grid.tsx +10 -4
- package/blocks/workbench/components/workbench-row-detail.tsx +104 -0
- package/blocks/workbench/components/workbench-screen.tsx +202 -0
- package/blocks/workbench/components/workbench-sources.tsx +194 -0
- package/blocks/workbench/components/workbench-table-list.tsx +14 -2
- package/blocks/workflows/README.md +13 -0
- package/blocks/workflows/block.json +28 -9
- package/blocks/workflows/components/run-history.tsx +31 -9
- package/blocks/workflows/components/trigger-config.tsx +3 -1
- package/blocks/workflows/components/workflow-editor.tsx +4 -2
- package/blocks/workflows/components/workflow-list.tsx +13 -6
- package/blocks/workflows/components/workflows-screen.tsx +193 -0
- package/dist/cli.js +3109 -1977
- package/dist/errors.d.mts +34 -0
- package/dist/errors.d.ts +34 -0
- package/dist/errors.js +46 -0
- package/dist/errors.js.map +1 -0
- package/dist/errors.mjs +21 -0
- package/dist/errors.mjs.map +1 -0
- package/dist/index.browser.js +11 -5
- package/dist/index.browser.js.map +1 -1
- package/dist/index.browser.mjs +11 -5
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.d.mts +164 -25
- package/dist/index.d.ts +164 -25
- package/dist/index.js +11 -5
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +11 -5
- package/dist/index.mjs.map +1 -1
- package/dist/react.browser.js +10 -4
- package/dist/react.browser.js.map +1 -1
- package/dist/react.browser.mjs +10 -4
- package/dist/react.browser.mjs.map +1 -1
- package/dist/react.d.mts +142 -5
- package/dist/react.d.ts +142 -5
- package/dist/react.js +10 -4
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +10 -4
- package/dist/react.mjs.map +1 -1
- package/dist/types/blocks/add.d.ts +11 -4
- package/dist/types/blocks/brand.d.ts +122 -0
- package/dist/types/blocks/compose.d.ts +53 -0
- package/dist/types/blocks/create.d.ts +27 -20
- package/dist/types/blocks/doctor.d.ts +6 -1
- package/dist/types/blocks/flows.d.ts +7 -1
- package/dist/types/blocks/navfile.d.ts +35 -0
- package/dist/types/blocks/orgBrand.d.ts +34 -0
- package/dist/types/blocks/paths.d.ts +4 -0
- package/dist/types/blocks/prefixes.d.ts +37 -0
- package/dist/types/blocks/registry.d.ts +17 -0
- package/dist/types/blocks/screens.d.ts +53 -0
- package/dist/types/cli.d.ts +5 -0
- package/dist/types/errors.d.ts +33 -0
- package/dist/types/http.d.ts +2 -18
- package/dist/types/version.d.ts +2 -2
- package/docs/agents.md +15 -4
- package/docs/api/README.md +2 -2
- package/docs/api/by-path.md +1 -0
- package/docs/api/desk.d.ts +98 -2
- package/docs/api/desk.md +123 -1
- package/docs/api/inbox.d.ts +10 -2
- package/docs/api/inbox.md +10 -2
- package/docs/api/seo.d.ts +19 -1
- package/docs/api/seo.md +24 -1
- package/package.json +16 -2
- package/stacks/6sense/pages/companies.tsx.tmpl +21 -0
- package/stacks/6sense/pages/contacts.tsx.tmpl +19 -0
- package/stacks/6sense/pages/tasks.tsx.tmpl +19 -0
- package/stacks/6sense.json +55 -17
- package/stacks/apollo/pages/calls.tsx.tmpl +23 -0
- package/stacks/apollo/pages/companies.tsx.tmpl +33 -0
- package/stacks/apollo/pages/contacts.tsx.tmpl +51 -0
- package/stacks/apollo/pages/deals.tsx.tmpl +17 -0
- package/stacks/apollo/pages/inbox-contact.tsx.tmpl +13 -0
- package/stacks/apollo/pages/lists.tsx.tmpl +12 -0
- package/stacks/apollo/pages/meetings.tsx.tmpl +13 -0
- package/stacks/apollo/pages/sequences.tsx.tmpl +12 -0
- package/stacks/apollo/pages/tasks.tsx.tmpl +20 -0
- package/stacks/apollo.json +147 -37
- package/stacks/calendly/pages/companies.tsx.tmpl +19 -0
- package/stacks/calendly/pages/contacts.tsx.tmpl +21 -0
- package/stacks/calendly/pages/meetings.tsx.tmpl +13 -0
- package/stacks/calendly/pages/tasks.tsx.tmpl +19 -0
- package/stacks/calendly.json +64 -0
- package/stacks/clay/pages/companies.tsx.tmpl +31 -0
- package/stacks/clay/pages/contacts.tsx.tmpl +31 -0
- package/stacks/clay/pages/lists.tsx.tmpl +12 -0
- package/stacks/clay/pages/tasks.tsx.tmpl +19 -0
- package/stacks/clay.json +73 -27
- package/stacks/gong/pages/calls.tsx.tmpl +23 -0
- package/stacks/gong/pages/companies.tsx.tmpl +22 -0
- package/stacks/gong/pages/contacts.tsx.tmpl +32 -0
- package/stacks/gong/pages/lists.tsx.tmpl +12 -0
- package/stacks/gong/pages/meetings.tsx.tmpl +13 -0
- package/stacks/gong/pages/tasks.tsx.tmpl +19 -0
- package/stacks/gong.json +98 -35
- package/stacks/hootsuite/pages/companies.tsx.tmpl +22 -0
- package/stacks/hootsuite/pages/contacts.tsx.tmpl +28 -0
- package/stacks/hootsuite/pages/lists.tsx.tmpl +12 -0
- package/stacks/hootsuite/pages/tasks.tsx.tmpl +19 -0
- package/stacks/hootsuite.json +104 -0
- package/stacks/hubspot/pages/companies.tsx.tmpl +26 -0
- package/stacks/hubspot/pages/contacts.tsx.tmpl +45 -0
- package/stacks/hubspot/pages/deals.tsx.tmpl +20 -0
- package/stacks/hubspot/pages/inbox.tsx.tmpl +103 -0
- package/stacks/hubspot/pages/lifecycle.tsx.tmpl +23 -0
- package/stacks/hubspot/pages/lists.tsx.tmpl +12 -0
- package/stacks/hubspot/pages/meetings.tsx.tmpl +13 -0
- package/stacks/hubspot/pages/quotes.tsx.tmpl +11 -0
- package/stacks/hubspot/pages/sequences.tsx.tmpl +12 -0
- package/stacks/hubspot/pages/tasks.tsx.tmpl +20 -0
- package/stacks/hubspot.json +181 -64
- package/stacks/intercom/pages/companies.tsx.tmpl +19 -0
- package/stacks/intercom/pages/contacts.tsx.tmpl +21 -0
- package/stacks/intercom/pages/inbox-contact.tsx.tmpl +13 -0
- package/stacks/intercom/pages/tasks.tsx.tmpl +19 -0
- package/stacks/intercom.json +52 -20
- package/stacks/mailchimp/pages/companies.tsx.tmpl +22 -0
- package/stacks/mailchimp/pages/contacts.tsx.tmpl +28 -0
- package/stacks/mailchimp/pages/lists.tsx.tmpl +12 -0
- package/stacks/mailchimp/pages/tasks.tsx.tmpl +19 -0
- package/stacks/mailchimp.json +68 -34
- package/stacks/outreach/pages/calls.tsx.tmpl +23 -0
- package/stacks/outreach/pages/companies.tsx.tmpl +22 -0
- package/stacks/outreach/pages/contacts.tsx.tmpl +46 -0
- package/stacks/outreach/pages/inbox-contact.tsx.tmpl +13 -0
- package/stacks/outreach/pages/lists.tsx.tmpl +12 -0
- package/stacks/outreach/pages/meetings.tsx.tmpl +13 -0
- package/stacks/outreach/pages/sequences.tsx.tmpl +12 -0
- package/stacks/outreach/pages/tasks.tsx.tmpl +19 -0
- package/stacks/outreach.json +106 -25
- package/stacks/pipedrive/pages/companies.tsx.tmpl +23 -0
- package/stacks/pipedrive/pages/contacts.tsx.tmpl +27 -0
- package/stacks/pipedrive/pages/deals.tsx.tmpl +20 -0
- package/stacks/pipedrive/pages/inbox.tsx.tmpl +103 -0
- package/stacks/pipedrive/pages/meetings.tsx.tmpl +13 -0
- package/stacks/pipedrive/pages/quotes.tsx.tmpl +11 -0
- package/stacks/pipedrive/pages/tasks.tsx.tmpl +20 -0
- package/stacks/pipedrive.json +117 -0
- package/stacks/salesforce/pages/companies.tsx.tmpl +26 -0
- package/stacks/salesforce/pages/contacts.tsx.tmpl +32 -0
- package/stacks/salesforce/pages/deals.tsx.tmpl +20 -0
- package/stacks/salesforce/pages/lifecycle.tsx.tmpl +23 -0
- package/stacks/salesforce/pages/lists.tsx.tmpl +12 -0
- package/stacks/salesforce/pages/quotes.tsx.tmpl +11 -0
- package/stacks/salesforce/pages/tasks.tsx.tmpl +20 -0
- package/stacks/salesforce.json +85 -31
- package/stacks/zoominfo/pages/companies.tsx.tmpl +31 -0
- package/stacks/zoominfo/pages/contacts.tsx.tmpl +31 -0
- package/stacks/zoominfo/pages/lists.tsx.tmpl +12 -0
- package/stacks/zoominfo/pages/tasks.tsx.tmpl +19 -0
- package/stacks/zoominfo.json +115 -0
- package/styles/styles.css +1 -1
- package/templates/next-app/README.md.tmpl +40 -9
- package/templates/next-app/app/globals.css.tmpl +349 -64
- package/templates/next-app/app/layout.tsx.tmpl +7 -2
- package/templates/next-app/components/app-shell.tsx.tmpl +104 -88
- package/templates/next-app/components/shell/quick-jump.tsx.tmpl +4 -0
- package/templates/next-app/dot-gitignore.tmpl +2 -0
- package/templates/next-app/package.json.tmpl +1 -1
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* MailboxesScreen: the finished "Mailboxes" settings page. Everything about the inboxes you send from.
|
|
5
|
+
*
|
|
6
|
+
* Composes: MailboxList, MailboxDetail (every field, warmup, test, archive, restore, delete), DomainDetail, WarmupHealth (fleet verdict, per-mailbox warmup and
|
|
7
|
+
* placement test), ConnectMailbox (IMAP/SMTP, Google/Microsoft link-out, buy mailboxes), DomainPurchase
|
|
8
|
+
* (suggest, check, buy, connect, DNS).
|
|
9
|
+
*
|
|
10
|
+
* User flows:
|
|
11
|
+
* - See fleet health at a glance (stat strip from the deliverability summary).
|
|
12
|
+
* - Every record opens a complete detail (MailboxDetail, DomainDetail) beside the list or as a full page
|
|
13
|
+
* (`?view=full`), deep-linked with `?id=`, `?tab=`, `?dtab=`.
|
|
14
|
+
* - Mailboxes tab: browse mailboxes, show archived (an archived one can be restored, confirmed), test a connection, archive or delete (confirmed),
|
|
15
|
+
* open one (deep link `?id=`) for warmup analytics, start/stop warmup and a confirmed placement test.
|
|
16
|
+
* - "Add mailbox" opens a sheet: connect over IMAP/SMTP, open the graph8 app for Google/Microsoft, or buy
|
|
17
|
+
* mailboxes on a connected domain (confirmed with a credit estimate).
|
|
18
|
+
* - Deliverability tab: the safe-to-send verdict, fleet counts and degraded mailboxes.
|
|
19
|
+
* - Domains tab: suggest, check availability, buy (confirmed), connect and check DNS propagation.
|
|
20
|
+
*
|
|
21
|
+
* SDK operations: none of its own, plus one read for the stat strip:
|
|
22
|
+
* getFleetSummary GET /deliverability/fleet-summary (read)
|
|
23
|
+
* Billable and destructive calls live in the composed parts and open ConfirmSpendDialog there.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import { useState } from "react";
|
|
27
|
+
import type { ReactNode } from "react";
|
|
28
|
+
import { Mail, Plus } from "lucide-react";
|
|
29
|
+
import { Button } from "@graph8/sdk/ui";
|
|
30
|
+
import { ScreenLayout } from "@/g8/components/screen/screen-layout";
|
|
31
|
+
import { SplitView } from "@/g8/components/screen/split-view";
|
|
32
|
+
import type { StatItem } from "@/g8/components/screen/stat-strip";
|
|
33
|
+
import { FormSheet } from "@/g8/components/screen/form-sheet";
|
|
34
|
+
import { StatusPill } from "@/g8/components/screen/status-pill";
|
|
35
|
+
import { Skeleton } from "@graph8/sdk/ui";
|
|
36
|
+
import { Toolbar } from "@/g8/components/screen/toolbar";
|
|
37
|
+
import { useUrlState } from "@/g8/hooks/use-url-state";
|
|
38
|
+
import { useG8Query } from "@/g8/hooks/use-g8-query";
|
|
39
|
+
import { g8Get } from "@/g8/lib/g8-client";
|
|
40
|
+
import { listOf, objectOf } from "../lib/mailboxes-utils";
|
|
41
|
+
import { useProviderDomains } from "../lib/use-provider-domains";
|
|
42
|
+
import type { DomainRow, MailboxRow } from "../lib/mailboxes-utils";
|
|
43
|
+
import { FirstNotice } from "@/g8/components/paging-notices";
|
|
44
|
+
import { ConnectMailbox } from "./connect-mailbox";
|
|
45
|
+
import { DomainPurchase } from "./domain-purchase";
|
|
46
|
+
import { DomainDetail } from "./domain-detail";
|
|
47
|
+
import { MailboxDetail } from "./mailbox-detail";
|
|
48
|
+
import { MailboxList } from "./mailbox-list";
|
|
49
|
+
import { WarmupHealth } from "./warmup-health";
|
|
50
|
+
|
|
51
|
+
export interface MailboxesScreenProps {
|
|
52
|
+
/** Where the person connects Google or Microsoft. Default: graph8 Settings > Purchase > Mailboxes. */
|
|
53
|
+
appUrl?: string;
|
|
54
|
+
/** Extra buttons in the toolbar. */
|
|
55
|
+
toolbarActions?: ReactNode;
|
|
56
|
+
/** Extra buttons in the open mailbox's header. */
|
|
57
|
+
renderDetailActions?: (mailbox: MailboxRow) => ReactNode;
|
|
58
|
+
/** Extra tabs in the open mailbox's panel. */
|
|
59
|
+
extraDetailTabs?: { id: string; label: string; render: (mailbox: MailboxRow) => ReactNode }[];
|
|
60
|
+
className?: string;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const TABS = [
|
|
64
|
+
{ id: "mailboxes", label: "Mailboxes" },
|
|
65
|
+
{ id: "deliverability", label: "Deliverability" },
|
|
66
|
+
{ id: "domains", label: "Domains" },
|
|
67
|
+
];
|
|
68
|
+
|
|
69
|
+
const STAT_ORDER = ["total", "healthy", "watch", "paused", "inbox_rate"];
|
|
70
|
+
|
|
71
|
+
function label(key: string): string {
|
|
72
|
+
const s = key.replace(/_/g, " ");
|
|
73
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Up to four numeric fleet fields; a 0..1 rate reads as a percent. Unknown shapes just show what is there. */
|
|
77
|
+
export function fleetStats(summary: Record<string, unknown>): StatItem[] {
|
|
78
|
+
const nums = Object.entries(summary).filter(([, v]) => typeof v === "number") as Array<[string, number]>;
|
|
79
|
+
nums.sort((a, b) => (STAT_ORDER.indexOf(a[0]) + 1 || 99) - (STAT_ORDER.indexOf(b[0]) + 1 || 99));
|
|
80
|
+
return nums.slice(0, 4).map(([k, v]) => ({
|
|
81
|
+
label: label(k),
|
|
82
|
+
value: k.includes("rate") && v <= 1 ? `${Math.round(v * 100)}%` : v.toLocaleString(),
|
|
83
|
+
tone: k === "healthy" ? "positive" : k === "watch" ? "warning" : undefined,
|
|
84
|
+
}));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function DomainList({ version, selectedId, onOpen }: { version: number; selectedId: string; onOpen: (d: DomainRow) => void }) {
|
|
88
|
+
const q = useProviderDomains([version]);
|
|
89
|
+
const rows = q.items;
|
|
90
|
+
if (q.loading && !q.loaded) return <Skeleton className="h-24 w-full" />;
|
|
91
|
+
if (rows.length === 0) return null;
|
|
92
|
+
return (
|
|
93
|
+
<>
|
|
94
|
+
<ul aria-label="Your domains" className="divide-y rounded-md border">
|
|
95
|
+
{rows.map((d) => (
|
|
96
|
+
<li key={d.id} className={`flex items-center justify-between px-3 py-2 text-sm ${String(d.id) === selectedId ? "bg-muted" : ""}`}>
|
|
97
|
+
<button type="button" className="font-medium hover:underline" onClick={() => onOpen(d)}>{d.domain}</button>
|
|
98
|
+
<span className="flex items-center gap-2">
|
|
99
|
+
{d.mailbox_count != null ? <span className="text-xs text-muted-foreground">{d.mailbox_count} mailboxes</span> : null}
|
|
100
|
+
<StatusPill tone={d.provider_connected ? "positive" : "warning"} dot>{d.provider_connected ? "Connected" : "Not connected"}</StatusPill>
|
|
101
|
+
</span>
|
|
102
|
+
</li>
|
|
103
|
+
))}
|
|
104
|
+
</ul>
|
|
105
|
+
<FirstNotice shown={rows.length} limit={rows.length} force={q.truncated} noun="domains" />
|
|
106
|
+
</>
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function MailboxesScreen({ appUrl, toolbarActions, renderDetailActions, extraDetailTabs, className }: MailboxesScreenProps) {
|
|
111
|
+
const [tab, setTab] = useUrlState("tab", "mailboxes");
|
|
112
|
+
const [selectedId, setSelectedId] = useUrlState("id", "");
|
|
113
|
+
const [detailTab, setDetailTab] = useUrlState("dtab", "");
|
|
114
|
+
const [view, setView] = useUrlState("view", "");
|
|
115
|
+
const [archived, setArchived] = useState(false);
|
|
116
|
+
const [adding, setAdding] = useState<{ domainId?: number | string } | null>(null);
|
|
117
|
+
const [version, setVersion] = useState(0);
|
|
118
|
+
const summary = useG8Query((signal) => g8Get("/deliverability/fleet-summary", undefined, { signal }), [version]);
|
|
119
|
+
const stats = fleetStats(objectOf(summary.data));
|
|
120
|
+
const bump = () => setVersion((v) => v + 1);
|
|
121
|
+
|
|
122
|
+
const go = (nextTab: string, id: string) => {
|
|
123
|
+
setTab(nextTab === "mailboxes" ? null : nextTab);
|
|
124
|
+
setSelectedId(id || null);
|
|
125
|
+
setDetailTab(null);
|
|
126
|
+
setView(null);
|
|
127
|
+
};
|
|
128
|
+
const close = () => { setSelectedId(null); setDetailTab(null); setView(null); };
|
|
129
|
+
const add = (
|
|
130
|
+
<Button onClick={() => setAdding({})}>
|
|
131
|
+
<Plus className="mr-1 h-4 w-4" aria-hidden /> Add mailbox
|
|
132
|
+
</Button>
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
return (
|
|
136
|
+
<ScreenLayout
|
|
137
|
+
className={className}
|
|
138
|
+
title="Mailboxes"
|
|
139
|
+
description="The inboxes you send from: connect, warm up and keep them healthy."
|
|
140
|
+
icon={<Mail className="h-5 w-5" aria-hidden />}
|
|
141
|
+
actions={add}
|
|
142
|
+
tabs={TABS}
|
|
143
|
+
activeTab={TABS.some((t) => t.id === tab) ? tab : "mailboxes"}
|
|
144
|
+
onTabChange={(id) => go(id, "")}
|
|
145
|
+
stats={stats.length > 0 ? stats : undefined}
|
|
146
|
+
>
|
|
147
|
+
{tab === "deliverability" ? (
|
|
148
|
+
<WarmupHealth />
|
|
149
|
+
) : tab === "domains" ? (
|
|
150
|
+
<SplitView
|
|
151
|
+
expanded={view === "full"} onExpandedChange={(e) => setView(e ? "full" : null)}
|
|
152
|
+
detailOpen={Boolean(selectedId)}
|
|
153
|
+
onCloseDetail={close}
|
|
154
|
+
list={
|
|
155
|
+
<div className="space-y-4">
|
|
156
|
+
<DomainList version={version} selectedId={selectedId} onOpen={(d) => go("domains", String(d.id))} />
|
|
157
|
+
<DomainPurchase onPurchased={bump} />
|
|
158
|
+
</div>
|
|
159
|
+
}
|
|
160
|
+
detail={
|
|
161
|
+
selectedId ? (
|
|
162
|
+
<DomainDetail
|
|
163
|
+
key={selectedId}
|
|
164
|
+
domainId={selectedId}
|
|
165
|
+
onExpand={view === "full" ? undefined : () => setView("full")} onCollapse={view === "full" ? () => setView(null) : undefined}
|
|
166
|
+
onClose={close}
|
|
167
|
+
onChanged={bump}
|
|
168
|
+
onBuyMailboxes={(d) => setAdding({ domainId: d.id })}
|
|
169
|
+
onOpenMailbox={(m) => go("mailboxes", m.id)}
|
|
170
|
+
/>
|
|
171
|
+
) : null
|
|
172
|
+
}
|
|
173
|
+
/>
|
|
174
|
+
) : (
|
|
175
|
+
<div className="space-y-3">
|
|
176
|
+
<Toolbar
|
|
177
|
+
actions={toolbarActions}
|
|
178
|
+
filters={
|
|
179
|
+
<label className="flex items-center gap-2 text-sm text-muted-foreground">
|
|
180
|
+
<input type="checkbox" checked={archived} onChange={(e) => setArchived(e.target.checked)} />
|
|
181
|
+
Show archived
|
|
182
|
+
</label>
|
|
183
|
+
}
|
|
184
|
+
/>
|
|
185
|
+
<SplitView
|
|
186
|
+
expanded={view === "full"} onExpandedChange={(e) => setView(e ? "full" : null)}
|
|
187
|
+
detailOpen={Boolean(selectedId)}
|
|
188
|
+
onCloseDetail={close}
|
|
189
|
+
list={<MailboxList key={`${version}:${archived}`} includeArchived={archived} onSelect={(m) => go("mailboxes", m.id)} emptyAction={add} />}
|
|
190
|
+
detail={
|
|
191
|
+
selectedId ? (
|
|
192
|
+
<MailboxDetail
|
|
193
|
+
key={selectedId}
|
|
194
|
+
mailboxId={selectedId}
|
|
195
|
+
onExpand={view === "full" ? undefined : () => setView("full")} onCollapse={view === "full" ? () => setView(null) : undefined}
|
|
196
|
+
tab={detailTab || undefined}
|
|
197
|
+
onTabChange={(t) => setDetailTab(t === "details" ? null : t)}
|
|
198
|
+
onClose={close}
|
|
199
|
+
onChanged={bump}
|
|
200
|
+
onOpenDomain={(d) => go("domains", String(d.id))}
|
|
201
|
+
renderActions={renderDetailActions}
|
|
202
|
+
extraTabs={extraDetailTabs}
|
|
203
|
+
/>
|
|
204
|
+
) : null
|
|
205
|
+
}
|
|
206
|
+
/>
|
|
207
|
+
</div>
|
|
208
|
+
)}
|
|
209
|
+
<FormSheet
|
|
210
|
+
width="lg"
|
|
211
|
+
open={adding !== null}
|
|
212
|
+
onOpenChange={(o) => !o && setAdding(null)}
|
|
213
|
+
title={adding?.domainId != null ? "Buy mailboxes" : "Add a mailbox"}
|
|
214
|
+
description="Connect one you own, use Google or Microsoft, or buy new ones."
|
|
215
|
+
>
|
|
216
|
+
{adding ? (
|
|
217
|
+
<ConnectMailbox
|
|
218
|
+
appUrl={appUrl}
|
|
219
|
+
initialMode={adding.domainId != null ? "buy" : "imap"}
|
|
220
|
+
domainId={adding.domainId}
|
|
221
|
+
onConnected={() => { setAdding(null); bump(); }}
|
|
222
|
+
onPurchased={bump}
|
|
223
|
+
/>
|
|
224
|
+
) : null}
|
|
225
|
+
</FormSheet>
|
|
226
|
+
</ScreenLayout>
|
|
227
|
+
);
|
|
228
|
+
}
|
|
@@ -29,6 +29,8 @@ import { listOf, objectOf, PLACEMENT_TEST_CREDITS, scalars, statusClass } from "
|
|
|
29
29
|
export interface WarmupHealthProps {
|
|
30
30
|
/** Show warmup analytics and controls for this mailbox (an id from MailboxList). */
|
|
31
31
|
mailboxId?: string | number;
|
|
32
|
+
/** Show the fleet verdict and counts above the mailbox section. Default true; screens that already show them pass false. */
|
|
33
|
+
showFleet?: boolean;
|
|
32
34
|
className?: string;
|
|
33
35
|
}
|
|
34
36
|
|
|
@@ -79,29 +81,29 @@ function Fleet() {
|
|
|
79
81
|
{safe === false ? "Not safe to send right now" : safe === true ? "Safe to send" : "Send status unknown"}
|
|
80
82
|
</p>
|
|
81
83
|
{verdict.error ? (
|
|
82
|
-
<p className="text-sm text-
|
|
84
|
+
<p className="text-sm text-warning-foreground">
|
|
83
85
|
The deliverability check failed, so sending is not confirmed safe. Retry before you send.
|
|
84
86
|
</p>
|
|
85
87
|
) : null}
|
|
86
|
-
{typeof v.reason === "string" ? <p className="text-sm text-
|
|
88
|
+
{typeof v.reason === "string" ? <p className="text-sm text-foreground">{v.reason}</p> : null}
|
|
87
89
|
</div>
|
|
88
90
|
<dl className="grid grid-cols-2 gap-2 sm:grid-cols-4">
|
|
89
91
|
{scalars(objectOf(summary.data))
|
|
90
92
|
.filter(([k]) => k !== "safe to send")
|
|
91
93
|
.map(([k, val]) => (
|
|
92
|
-
<div key={k} className="rounded border border-
|
|
93
|
-
<dt className="text-xs capitalize text-
|
|
94
|
-
<dd className="text-lg font-
|
|
94
|
+
<div key={k} className="rounded border border-border p-2">
|
|
95
|
+
<dt className="text-xs capitalize text-muted-foreground">{k}</dt>
|
|
96
|
+
<dd className="text-lg font-medium">{val}</dd>
|
|
95
97
|
</div>
|
|
96
98
|
))}
|
|
97
99
|
</dl>
|
|
98
100
|
{rows.length > 0 ? (
|
|
99
|
-
<ul className="divide-y rounded border border-
|
|
101
|
+
<ul className="divide-y rounded border border-border" aria-label="Degraded mailboxes">
|
|
100
102
|
{rows.map((r, i) => (
|
|
101
103
|
<li key={String(r.id ?? i)} className="flex items-center justify-between px-3 py-2 text-sm">
|
|
102
104
|
<span>
|
|
103
105
|
{r.email ?? r.mailbox_email ?? `Mailbox ${r.id}`}
|
|
104
|
-
<span className="ml-2 text-xs text-
|
|
106
|
+
<span className="ml-2 text-xs text-muted-foreground">{r.reason ?? r.reasons?.join(", ")}</span>
|
|
105
107
|
</span>
|
|
106
108
|
<span className={`rounded px-2 py-0.5 text-xs ${statusClass(r.severity ?? r.status)}`}>
|
|
107
109
|
{r.severity ?? r.status ?? "watch"}
|
|
@@ -132,7 +134,7 @@ function MailboxWarmup({ mailboxId }: { mailboxId: string | number }) {
|
|
|
132
134
|
const w = warm.data?.data;
|
|
133
135
|
const a = w?.analytics;
|
|
134
136
|
return (
|
|
135
|
-
<section className="space-y-3 rounded border border-
|
|
137
|
+
<section className="space-y-3 rounded border border-border p-3" aria-label="Warmup">
|
|
136
138
|
<div className="flex items-center justify-between">
|
|
137
139
|
<h3 className="font-medium">
|
|
138
140
|
Warmup {w?.warmup_enabled ? "is on" : "is off"}
|
|
@@ -153,7 +155,7 @@ function MailboxWarmup({ mailboxId }: { mailboxId: string | number }) {
|
|
|
153
155
|
</div>
|
|
154
156
|
</div>
|
|
155
157
|
{w?.error ? (
|
|
156
|
-
<p role="alert" className="text-sm text-
|
|
158
|
+
<p role="alert" className="text-sm text-warning-foreground">
|
|
157
159
|
The warmup provider did not answer: {w.error}
|
|
158
160
|
</p>
|
|
159
161
|
) : null}
|
|
@@ -161,22 +163,22 @@ function MailboxWarmup({ mailboxId }: { mailboxId: string | number }) {
|
|
|
161
163
|
<>
|
|
162
164
|
<dl className="grid grid-cols-2 gap-2 sm:grid-cols-4 text-sm">
|
|
163
165
|
<div>
|
|
164
|
-
<dt className="text-xs text-
|
|
165
|
-
<dd className="font-
|
|
166
|
+
<dt className="text-xs text-muted-foreground">Sent</dt>
|
|
167
|
+
<dd className="font-medium">{a.total_sent ?? 0}</dd>
|
|
166
168
|
</div>
|
|
167
169
|
<div>
|
|
168
|
-
<dt className="text-xs text-
|
|
169
|
-
<dd className="font-
|
|
170
|
+
<dt className="text-xs text-muted-foreground">Inbox rate</dt>
|
|
171
|
+
<dd className="font-medium">
|
|
170
172
|
{a.inbox_rate != null ? `${Math.round(a.inbox_rate <= 1 ? a.inbox_rate * 100 : a.inbox_rate)}%` : "-"}
|
|
171
173
|
</dd>
|
|
172
174
|
</div>
|
|
173
175
|
<div>
|
|
174
|
-
<dt className="text-xs text-
|
|
175
|
-
<dd className="font-
|
|
176
|
+
<dt className="text-xs text-muted-foreground">Spam</dt>
|
|
177
|
+
<dd className="font-medium">{a.total_spam ?? 0}</dd>
|
|
176
178
|
</div>
|
|
177
179
|
<div>
|
|
178
|
-
<dt className="text-xs text-
|
|
179
|
-
<dd className="font-
|
|
180
|
+
<dt className="text-xs text-muted-foreground">Reputation</dt>
|
|
181
|
+
<dd className="font-medium">{a.reputation ?? "-"}</dd>
|
|
180
182
|
</div>
|
|
181
183
|
</dl>
|
|
182
184
|
{(a.daily_stats ?? []).length > 0 ? (
|
|
@@ -185,7 +187,7 @@ function MailboxWarmup({ mailboxId }: { mailboxId: string | number }) {
|
|
|
185
187
|
<span
|
|
186
188
|
key={d.date}
|
|
187
189
|
title={`${d.date}: ${d.sent} sent, ${d.inbox} inbox`}
|
|
188
|
-
className="w-2 rounded-t bg-
|
|
190
|
+
className="w-2 rounded-t bg-foreground/70"
|
|
189
191
|
style={{ height: `${Math.max(4, Math.min(100, d.sent * 4))}%` }}
|
|
190
192
|
/>
|
|
191
193
|
))}
|
|
@@ -193,7 +195,7 @@ function MailboxWarmup({ mailboxId }: { mailboxId: string | number }) {
|
|
|
193
195
|
) : null}
|
|
194
196
|
</>
|
|
195
197
|
) : (
|
|
196
|
-
<p className="text-sm text-
|
|
198
|
+
<p className="text-sm text-muted-foreground">No warmup analytics yet.</p>
|
|
197
199
|
)}
|
|
198
200
|
<Button size="sm" variant="outline" onClick={() => setConfirm(true)}>
|
|
199
201
|
Run placement test
|
|
@@ -201,7 +203,7 @@ function MailboxWarmup({ mailboxId }: { mailboxId: string | number }) {
|
|
|
201
203
|
{toggle.error ? <ApiError error={toggle.error} onRetry={toggle.reset} /> : null}
|
|
202
204
|
{placement.error ? <ApiError error={placement.error} onRetry={placement.reset} /> : null}
|
|
203
205
|
{note ? (
|
|
204
|
-
<p role="status" className="text-sm text-
|
|
206
|
+
<p role="status" className="text-sm text-positive-foreground">
|
|
205
207
|
{note}
|
|
206
208
|
</p>
|
|
207
209
|
) : null}
|
|
@@ -222,10 +224,10 @@ function MailboxWarmup({ mailboxId }: { mailboxId: string | number }) {
|
|
|
222
224
|
);
|
|
223
225
|
}
|
|
224
226
|
|
|
225
|
-
export function WarmupHealth({ mailboxId, className }: WarmupHealthProps) {
|
|
227
|
+
export function WarmupHealth({ mailboxId, showFleet = true, className }: WarmupHealthProps) {
|
|
226
228
|
return (
|
|
227
229
|
<div className={`space-y-4 ${className ?? ""}`}>
|
|
228
|
-
<Fleet />
|
|
230
|
+
{showFleet || mailboxId == null ? <Fleet /> : null}
|
|
229
231
|
{mailboxId != null ? <MailboxWarmup mailboxId={mailboxId} /> : null}
|
|
230
232
|
</div>
|
|
231
233
|
);
|
|
@@ -2,8 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
/** Types and helpers shared by the mailbox components. Open-shaped payloads: every field is optional. */
|
|
4
4
|
|
|
5
|
+
import { DEFAULT_BRAND } from "@/g8/hooks/use-brand";
|
|
6
|
+
|
|
5
7
|
/** Where the person connects a Google or Microsoft mailbox. OAuth consent can only run in the graph8 app. */
|
|
6
|
-
|
|
8
|
+
/** The path on the platform's web app; components resolve it against the brand (`brandUrl(useBrand(), ...)`). */
|
|
9
|
+
export const GRAPH8_APP_MAILBOXES_PATH = "/studio/settings?tab=purchase&view=mailboxes";
|
|
10
|
+
/** The default (graph8) URL. Kept for existing imports; prefer GRAPH8_APP_MAILBOXES_PATH with useBrand. */
|
|
11
|
+
export const GRAPH8_APP_MAILBOXES_URL = `${DEFAULT_BRAND.appUrl}${GRAPH8_APP_MAILBOXES_PATH}`;
|
|
7
12
|
|
|
8
13
|
/** The API holds these when you buy (docs/developer-api-reference.md, Channel Purchase); the real rate can change. */
|
|
9
14
|
export const DEFAULT_DOMAIN_CREDITS = 2500;
|
|
@@ -48,10 +53,10 @@ export function objectOf(envelope: unknown): Record<string, unknown> {
|
|
|
48
53
|
/** Tailwind classes for a connection or health state. */
|
|
49
54
|
export function statusClass(status: string | null | undefined): string {
|
|
50
55
|
const s = (status ?? "").toLowerCase();
|
|
51
|
-
if (["active", "connected", "healthy", "completed", "receiving"].includes(s)) return "bg-
|
|
52
|
-
if (["paused", "watch", "warming", "pending", "connecting", "provisioning"].includes(s)) return "bg-
|
|
53
|
-
if (s) return "bg-
|
|
54
|
-
return "bg-
|
|
56
|
+
if (["active", "connected", "healthy", "completed", "receiving"].includes(s)) return "bg-positive text-positive-foreground";
|
|
57
|
+
if (["paused", "watch", "warming", "pending", "connecting", "provisioning"].includes(s)) return "bg-warning text-warning-foreground";
|
|
58
|
+
if (s) return "bg-error text-error-foreground";
|
|
59
|
+
return "bg-muted text-foreground";
|
|
55
60
|
}
|
|
56
61
|
|
|
57
62
|
/** Scalar fields of an open-shaped object, for a summary grid. */
|
|
@@ -67,3 +72,19 @@ export function newIdempotencyKey(): string {
|
|
|
67
72
|
? crypto.randomUUID()
|
|
68
73
|
: `g8-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
69
74
|
}
|
|
75
|
+
|
|
76
|
+
const HIDDEN_FIELDS = /password|secret|token|credential/i;
|
|
77
|
+
|
|
78
|
+
/** Every readable field of an open-shaped record as label/value pairs (secrets are never shown). */
|
|
79
|
+
export function fieldItems(obj: Record<string, unknown>): Array<{ label: string; value: string }> {
|
|
80
|
+
return Object.entries(obj)
|
|
81
|
+
.filter(([k, v]) => !HIDDEN_FIELDS.test(k) && v !== null && v !== undefined && v !== "")
|
|
82
|
+
.map(([k, v]) => {
|
|
83
|
+
const label = k.replace(/_/g, " ").replace(/^./, (c) => c.toUpperCase());
|
|
84
|
+
if (typeof v === "string" && /_at$|date$/.test(k) && !Number.isNaN(new Date(v).getTime()))
|
|
85
|
+
return { label, value: new Date(v).toLocaleString("en-US", { dateStyle: "medium", timeStyle: "short", timeZone: "UTC" }) + " UTC" };
|
|
86
|
+
if (typeof v === "boolean") return { label, value: v ? "Yes" : "No" };
|
|
87
|
+
if (typeof v === "object") return { label, value: JSON.stringify(v) };
|
|
88
|
+
return { label, value: String(v) };
|
|
89
|
+
});
|
|
90
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* useProviderDomains: every sending domain of the workspace. The domains API pages (`page`, `limit`), so this reads page
|
|
5
|
+
* after page (100 per page, up to 20 pages) instead of one capped call; `truncated` says the page cap was reached.
|
|
6
|
+
*
|
|
7
|
+
* SDK operations: GET /provider-domains?page&limit (providerDomains.listProviderDomains) read
|
|
8
|
+
*/
|
|
9
|
+
import { g8Get } from "@/g8/lib/g8-client";
|
|
10
|
+
import { useAllPages } from "@/g8/hooks/use-all-pages";
|
|
11
|
+
import { hasNextOf } from "@/g8/lib/paging";
|
|
12
|
+
import { listOf } from "./mailboxes-utils";
|
|
13
|
+
import type { DomainRow } from "./mailboxes-utils";
|
|
14
|
+
|
|
15
|
+
export const DOMAIN_PAGE = 100;
|
|
16
|
+
|
|
17
|
+
export function useProviderDomains(deps: readonly unknown[] = [], enabled = true) {
|
|
18
|
+
return useAllPages<DomainRow>(async (page, signal) => {
|
|
19
|
+
const env = await g8Get("/provider-domains", { page, limit: DOMAIN_PAGE }, { signal });
|
|
20
|
+
const rows = listOf<DomainRow>(env);
|
|
21
|
+
return { rows, hasNext: hasNextOf(env, DOMAIN_PAGE, rows.length) };
|
|
22
|
+
}, deps, { enabled });
|
|
23
|
+
}
|
|
@@ -133,3 +133,15 @@ Tiers: `read` and `write` need no confirmation; `billable`, `external` and `dest
|
|
|
133
133
|
| `newsletter.unsubscribeSubscriber` | `PATCH /api/v1/newsletters/{newsletter_id}/subscribers/{subscriber_id}/unsubscribe` | external | `newsletter:run` | SubscriberTable |
|
|
134
134
|
| `newsletter.deleteSubscriber` | `DELETE /api/v1/newsletters/{newsletter_id}/subscribers/{subscriber_id}` | destructive | `newsletter:delete` | SubscriberTable |
|
|
135
135
|
| `newsletter.getIssueAnalyticsKpis` | `GET /api/v1/newsletters/{newsletter_id}/issues/{issue_id}/analytics/kpis` | read | `newsletter:read` | NewsletterStats |
|
|
136
|
+
|
|
137
|
+
## Depth added (C7c)
|
|
138
|
+
|
|
139
|
+
New tabs on `NewsletterScreen`: **Templates**, **Lists**, **Settings**; issues gain a **History** tab; a subscriber shows **Activity on an issue**.
|
|
140
|
+
|
|
141
|
+
- `NewsletterSettings`: rename and goal, sender and opt-in policy (only changed fields are sent), sending domain (start verification is an external confirm, DNS records are listed, status check), resume a paused newsletter (external confirm), mark completed.
|
|
142
|
+
- `NewsletterListSyncs`: turn a list sync on (the consent statement is shown and sent), run it now, stop it (destructive). Lists page with Load more.
|
|
143
|
+
- `NewsletterTemplates`: use a template for a draft issue, approve or archive, rename, delete (destructive), write one with AI (billable confirm).
|
|
144
|
+
- `IssueVersions`: version history with restore (drafts only, second click) and Duplicate (external confirm).
|
|
145
|
+
- `SubscriberTimeline`: delivered, opened and clicked for one subscriber on one sent issue.
|
|
146
|
+
|
|
147
|
+
Not covered (and why): `rewriteIssueText`, `setIssueText`, `setIssueMediaEdit`, `setIssueButtonAction` and the template equivalents need element ids the HTML editor does not expose; `linkNewsletterCampaign` needs a campaign picker (owned by the pickers PR); `cloneTemplate`, `createTemplateFromLayout` and `batchTemplateGenerationStatus` are template-gallery flows; `getNewsletterSubscriberVerification` status is not shown (verify still runs and reports through the existing flow); `getNewsletterIssueConversation` is the hosted editor's chat. The subscriber and list pickers keep their existing paging.
|