@graph8/sdk 0.370.0 → 0.374.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -3
- package/blocks/_foundation/README.md +61 -0
- package/blocks/_foundation/block.json +57 -0
- package/blocks/_foundation/components/auth-gate.tsx +363 -0
- package/blocks/_foundation/components/confirm-spend-dialog.tsx +15 -8
- 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 +1 -0
- package/blocks/_foundation/components/screen/split-view.tsx +1 -1
- package/blocks/_foundation/hooks/use-all-pages.ts +54 -0
- package/blocks/_foundation/hooks/use-load-more-list.ts +61 -0
- package/blocks/_foundation/hooks/use-url-filters.ts +93 -0
- package/blocks/_foundation/lib/paging.ts +57 -0
- package/blocks/_foundation/lib/use-debounced-value.ts +13 -0
- package/blocks/_foundation/server/auth.ts +815 -0
- package/blocks/agents/README.md +81 -4
- package/blocks/agents/block.json +311 -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 +17 -3
- package/blocks/agents/components/agent-conversations.tsx +143 -0
- package/blocks/agents/components/agent-knowledge-panel.tsx +2 -2
- package/blocks/agents/components/agent-operators.tsx +164 -0
- package/blocks/agents/components/agent-run-detail.tsx +20 -3
- package/blocks/agents/components/agent-runs.tsx +3 -3
- 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 +53 -11
- 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/components/analytics-screen.tsx +16 -3
- package/blocks/analytics/components/kpi-tiles.tsx +1 -1
- package/blocks/analytics/components/report-builder.tsx +15 -2
- package/blocks/appointments/README.md +6 -0
- package/blocks/appointments/block.json +27 -0
- package/blocks/appointments/components/booking-page.tsx +2 -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 +29 -13
- package/blocks/appointments/components/record-meetings-tab.tsx +92 -0
- package/blocks/campaigns/README.md +1 -1
- package/blocks/campaigns/block.json +34 -1
- package/blocks/campaigns/components/campaign-assets.tsx +1 -1
- package/blocks/campaigns/components/campaign-launch-step.tsx +16 -11
- package/blocks/campaigns/components/campaign-links.tsx +180 -0
- package/blocks/campaigns/components/campaign-metrics.tsx +1 -1
- package/blocks/campaigns/components/campaign-wizard.tsx +10 -5
- package/blocks/campaigns/components/icp-detail.tsx +11 -2
- package/blocks/campaigns/components/icp-editor.tsx +8 -3
- package/blocks/campaigns/components/persona-detail.tsx +11 -2
- package/blocks/campaigns/components/persona-editor.tsx +6 -1
- package/blocks/campaigns/lib/campaigns-utils.ts +4 -4
- package/blocks/coach/components/call-scorecard.tsx +7 -7
- 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 +165 -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/components/copilot-memory.tsx +6 -2
- package/blocks/copilot/components/copilot-panel.tsx +1 -1
- package/blocks/copilot/components/copilot-team-chat.tsx +6 -1
- package/blocks/crm/README.md +25 -0
- package/blocks/crm/block.json +257 -9
- package/blocks/crm/components/bulk-update.tsx +119 -0
- package/blocks/crm/components/companies-screen.tsx +23 -9
- package/blocks/crm/components/company-detail.tsx +2 -2
- package/blocks/crm/components/contact-detail.tsx +4 -4
- package/blocks/crm/components/contact-documents-tab.tsx +144 -0
- package/blocks/crm/components/contact-insights-tab.tsx +118 -0
- package/blocks/crm/components/contact-lookup-link.tsx +85 -0
- package/blocks/crm/components/contact-row-actions.tsx +43 -0
- package/blocks/crm/components/contact-tag-chips.tsx +113 -0
- package/blocks/crm/components/contacts-screen.tsx +77 -18
- package/blocks/crm/components/dedupe-review.tsx +6 -1
- package/blocks/crm/components/import-wizard.tsx +3 -7
- package/blocks/crm/components/list-select.tsx +20 -0
- package/blocks/crm/components/owner-assign.tsx +132 -0
- package/blocks/crm/components/record-engagement-tab.tsx +103 -0
- package/blocks/crm/components/record-form.tsx +1 -1
- package/blocks/crm/components/record-open-links.tsx +79 -0
- package/blocks/crm/components/tag-assign.tsx +112 -0
- package/blocks/crm/components/tag-manager.tsx +178 -0
- package/blocks/crm/components/tasks-screen.tsx +35 -15
- package/blocks/crm/components/unlock-info-button.tsx +82 -0
- package/blocks/crm/components/verify-email-button.tsx +93 -0
- package/blocks/crm/hooks/use-all-lists.ts +18 -0
- package/blocks/crm/hooks/use-contact-tags.ts +29 -0
- package/blocks/crm/hooks/use-page-query.ts +3 -1
- package/blocks/crm/lib/crm-types.ts +14 -0
- package/blocks/crm/lib/read-lists.ts +16 -0
- package/blocks/crm/lib/record-actions.ts +102 -0
- package/blocks/deals/README.md +25 -6
- package/blocks/deals/block.json +168 -2
- package/blocks/deals/components/close-deal-dialog.tsx +169 -0
- package/blocks/deals/components/create-deal-button.tsx +109 -0
- package/blocks/deals/components/deal-contacts-editor.tsx +134 -0
- package/blocks/deals/components/deal-detail.tsx +7 -5
- 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 +30 -9
- package/blocks/deals/components/deal-tasks-tab.tsx +88 -0
- package/blocks/deals/components/deals-screen.tsx +57 -22
- 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 +1 -1
- package/blocks/deals/hooks/use-pipeline-deals.ts +17 -4
- package/blocks/deals/lib/deal-extras.ts +156 -0
- package/blocks/dialer/README.md +14 -5
- package/blocks/dialer/block.json +17 -2
- package/blocks/dialer/components/call-contact-button.tsx +26 -9
- package/blocks/dialer/components/call-log-screen.tsx +10 -2
- package/blocks/dialer/components/call-log.tsx +16 -4
- package/blocks/dialer/components/call-queue.tsx +3 -3
- package/blocks/dialer/components/dialer-screen.tsx +69 -27
- package/blocks/dialer/components/disposition-panel.tsx +1 -1
- package/blocks/dialer/components/record-calls-tab.tsx +101 -0
- package/blocks/dialer/components/session-start-form.tsx +58 -11
- package/blocks/dialer/components/softphone.tsx +1 -1
- package/blocks/documents/README.md +86 -0
- package/blocks/documents/block.json +378 -0
- package/blocks/documents/components/account-bar.tsx +48 -0
- package/blocks/documents/components/correspondence-form.tsx +95 -0
- package/blocks/documents/components/correspondence-import.tsx +106 -0
- package/blocks/documents/components/correspondence-panel.tsx +191 -0
- package/blocks/documents/components/documents-screen.tsx +76 -0
- package/blocks/documents/components/library-document-detail.tsx +175 -0
- package/blocks/documents/components/library-document-form.tsx +105 -0
- package/blocks/documents/components/library-folder-form.tsx +74 -0
- package/blocks/documents/components/library-panel.tsx +235 -0
- package/blocks/documents/components/library-upload.tsx +160 -0
- package/blocks/documents/components/question-row.tsx +130 -0
- package/blocks/documents/components/questionnaire-detail.tsx +197 -0
- package/blocks/documents/components/questionnaires-panel.tsx +173 -0
- package/blocks/documents/components/record-documents-tab.tsx +109 -0
- package/blocks/documents/lib/documents-types.ts +252 -0
- package/blocks/documents/lib/download.ts +64 -0
- package/blocks/documents/recipes/follow-a-questionnaire.ts +26 -0
- package/blocks/documents/recipes/log-account-correspondence.ts +27 -0
- package/blocks/documents/recipes/organize-the-library.ts +25 -0
- package/blocks/email-signatures/README.md +123 -0
- package/blocks/email-signatures/block.json +341 -0
- package/blocks/email-signatures/components/email-signatures-screen.tsx +166 -0
- package/blocks/email-signatures/components/signature-assign-template.tsx +119 -0
- package/blocks/email-signatures/components/signature-block-editor.tsx +87 -0
- package/blocks/email-signatures/components/signature-campaign-form.tsx +165 -0
- package/blocks/email-signatures/components/signature-campaigns.tsx +75 -0
- package/blocks/email-signatures/components/signature-identity-form.tsx +131 -0
- package/blocks/email-signatures/components/signature-mailboxes.tsx +195 -0
- package/blocks/email-signatures/components/signature-policy.tsx +130 -0
- package/blocks/email-signatures/components/signature-preview.tsx +119 -0
- package/blocks/email-signatures/components/signature-report.tsx +77 -0
- package/blocks/email-signatures/components/signature-template-details.tsx +112 -0
- package/blocks/email-signatures/components/signature-template-form.tsx +109 -0
- package/blocks/email-signatures/hooks/use-signatures-data.ts +93 -0
- package/blocks/email-signatures/lib/signatures-types.ts +392 -0
- package/blocks/email-signatures/recipes/assign-a-signature-to-a-new-hire.ts +32 -0
- package/blocks/email-signatures/recipes/create-a-template-and-make-it-default.ts +35 -0
- package/blocks/email-signatures/recipes/signature-engagement-report.ts +16 -0
- package/blocks/enrichment/README.md +38 -10
- package/blocks/enrichment/block.json +164 -12
- package/blocks/enrichment/components/auto-enrichment-configs.tsx +134 -0
- package/blocks/enrichment/components/auto-enrichment-settings.tsx +82 -0
- package/blocks/enrichment/components/bulk-enrich-panel.tsx +79 -30
- package/blocks/enrichment/components/email-verify-badge.tsx +3 -3
- package/blocks/enrichment/components/enrich-button.tsx +1 -1
- package/blocks/enrichment/components/enrichment-activity.tsx +93 -0
- package/blocks/enrichment/components/enrichment-job-detail.tsx +18 -0
- package/blocks/enrichment/components/enrichment-screen.tsx +103 -19
- package/blocks/enrichment/components/list-pipelines.tsx +97 -0
- package/blocks/enrichment/components/pipeline-detail.tsx +214 -0
- package/blocks/enrichment/components/pipeline-editor.tsx +144 -0
- package/blocks/enrichment/components/pipeline-templates.tsx +90 -0
- package/blocks/enrichment/components/waterfall-config.tsx +27 -7
- package/blocks/enrichment/lib/enrichment-types.ts +51 -0
- package/blocks/enrichment/lib/pipeline-types.ts +234 -0
- package/blocks/enrichment/recipes/bulk-enrich-and-poll.ts +15 -4
- package/blocks/forms/README.md +10 -0
- package/blocks/forms/block.json +107 -0
- 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 +1 -1
- package/blocks/forms/components/form-embed.tsx +1 -1
- 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 +57 -20
- 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 +15 -6
- package/blocks/forms/lib/forms-extra.ts +67 -0
- package/blocks/inbox/README.md +45 -4
- package/blocks/inbox/block.json +145 -8
- package/blocks/inbox/components/blocked-senders.tsx +103 -0
- package/blocks/inbox/components/compose-message.tsx +193 -0
- package/blocks/inbox/components/inbox-screen.tsx +54 -6
- package/blocks/inbox/components/inbox-search.tsx +106 -0
- package/blocks/inbox/components/record-conversations-tab.tsx +154 -0
- package/blocks/inbox/components/tag-manager.tsx +136 -0
- package/blocks/inbox/components/thread-actions.tsx +133 -0
- package/blocks/inbox/components/thread-badge.tsx +2 -2
- package/blocks/inbox/components/thread-view.tsx +3 -1
- package/blocks/inbox/hooks/use-inbox-mailboxes.ts +31 -0
- package/blocks/inbox/lib/inbox-manage.ts +227 -0
- package/blocks/integrations/README.md +54 -1
- package/blocks/integrations/block.json +189 -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 +20 -1
- 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 +4 -4
- package/blocks/integrations/components/integrations-screen.tsx +20 -3
- 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 +6 -6
- package/blocks/integrations/components/sync-triggers.tsx +134 -0
- package/blocks/integrations/components/webhook-detail.tsx +26 -7
- package/blocks/integrations/components/webhook-manager.tsx +30 -17
- 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 +5 -0
- package/blocks/integrations/lib/load-more.tsx +141 -0
- package/blocks/intent/components/account-intent-score.tsx +5 -5
- package/blocks/intent/components/intent-feed.tsx +8 -8
- package/blocks/intent/components/intent-keyword-manager.tsx +8 -8
- package/blocks/intent/lib/intent-utils.ts +4 -4
- 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/lists/README.md +7 -1
- package/blocks/lists/block.json +31 -3
- package/blocks/lists/components/add-company-people-to-list-button.tsx +73 -0
- package/blocks/lists/components/add-to-list-button.tsx +17 -7
- package/blocks/lists/components/list-picker.tsx +13 -3
- package/blocks/lists/components/list-table.tsx +1 -1
- package/blocks/lists/components/lists-screen.tsx +4 -2
- package/blocks/lists/components/record-lists-tab.tsx +99 -0
- package/blocks/lists/components/suppression-manager.tsx +27 -6
- package/blocks/lists/components/suppressions-screen.tsx +21 -12
- package/blocks/mailboxes/block.json +4 -0
- package/blocks/mailboxes/components/connect-mailbox.tsx +9 -8
- package/blocks/mailboxes/components/domain-detail.tsx +10 -4
- package/blocks/mailboxes/components/domain-purchase.tsx +14 -11
- package/blocks/mailboxes/components/mailbox-detail.tsx +3 -2
- package/blocks/mailboxes/components/mailbox-list.tsx +8 -3
- package/blocks/mailboxes/components/mailboxes-screen.tsx +8 -3
- package/blocks/mailboxes/components/warmup-health.tsx +20 -20
- package/blocks/mailboxes/lib/mailboxes-utils.ts +4 -4
- package/blocks/mailboxes/lib/use-provider-domains.ts +23 -0
- package/blocks/newsletter/README.md +12 -0
- package/blocks/newsletter/block.json +117 -0
- package/blocks/newsletter/components/issue-scheduler.tsx +2 -2
- 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 +38 -13
- 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/components/nurture-builder.tsx +10 -2
- package/blocks/nurture/components/nurture-enroll.tsx +6 -7
- package/blocks/nurture/components/nurture-form.tsx +5 -8
- package/blocks/nurture/components/nurture-screen.tsx +16 -5
- package/blocks/nurture/components/nurture-stats.tsx +5 -4
- package/blocks/objects/README.md +1 -1
- package/blocks/objects/block.json +13 -5
- package/blocks/objects/components/attribute-field-input.tsx +14 -1
- package/blocks/objects/components/object-record-detail.tsx +8 -1
- package/blocks/objects/components/object-schema-editor.tsx +1 -1
- package/blocks/objects/components/record-roles-panel.tsx +15 -5
- package/blocks/pages/README.md +14 -0
- package/blocks/pages/block.json +123 -2
- 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-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/hooks/use-landing-page-paths.ts +60 -0
- 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/programmatic-pages/README.md +82 -0
- package/blocks/programmatic-pages/block.json +292 -0
- package/blocks/programmatic-pages/components/programmatic-campaign-form.tsx +136 -0
- package/blocks/programmatic-pages/components/programmatic-generate.tsx +112 -0
- package/blocks/programmatic-pages/components/programmatic-generated-pages.tsx +210 -0
- package/blocks/programmatic-pages/components/programmatic-overview.tsx +84 -0
- package/blocks/programmatic-pages/components/programmatic-pages-screen.tsx +221 -0
- package/blocks/programmatic-pages/components/programmatic-preview.tsx +66 -0
- package/blocks/programmatic-pages/components/programmatic-publish.tsx +102 -0
- package/blocks/programmatic-pages/components/programmatic-settings.tsx +96 -0
- package/blocks/programmatic-pages/components/programmatic-source-fields.tsx +75 -0
- package/blocks/programmatic-pages/components/programmatic-source.tsx +106 -0
- package/blocks/programmatic-pages/components/programmatic-variables.tsx +84 -0
- package/blocks/programmatic-pages/hooks/use-programmatic-workspace.ts +19 -0
- package/blocks/programmatic-pages/lib/programmatic-types.ts +330 -0
- package/blocks/programmatic-pages/recipes/create-a-programmatic-campaign.ts +23 -0
- package/blocks/programmatic-pages/recipes/render-and-follow.ts +21 -0
- package/blocks/programmatic-pages/recipes/review-then-publish.ts +17 -0
- package/blocks/quotes/README.md +38 -1
- package/blocks/quotes/block.json +170 -6
- package/blocks/quotes/components/create-quote-from-deal.tsx +48 -0
- package/blocks/quotes/components/manual-products.tsx +144 -0
- package/blocks/quotes/components/quote-batch-actions.tsx +86 -0
- package/blocks/quotes/components/quote-builder.tsx +1 -1
- package/blocks/quotes/components/quote-documents.tsx +94 -0
- package/blocks/quotes/components/quote-evidence.tsx +95 -0
- package/blocks/quotes/components/quote-lifecycle-actions.tsx +146 -0
- package/blocks/quotes/components/quote-list.tsx +28 -8
- package/blocks/quotes/components/quote-related.tsx +3 -2
- package/blocks/quotes/components/quote-settings.tsx +184 -0
- package/blocks/quotes/components/quote-templates.tsx +189 -0
- package/blocks/quotes/components/quote-viewer.tsx +23 -5
- package/blocks/quotes/components/quotes-screen.tsx +15 -5
- package/blocks/quotes/components/record-quotes-tab.tsx +90 -0
- package/blocks/quotes/lib/quote-admin.ts +264 -0
- package/blocks/radar/components/competitor-battle-card.tsx +1 -1
- package/blocks/radar/components/radar-overview.tsx +4 -4
- package/blocks/radar/components/radar-screen.tsx +2 -2
- package/blocks/sequencer/README.md +61 -0
- package/blocks/sequencer/block.json +200 -6
- package/blocks/sequencer/components/add-to-sequence-button.tsx +82 -0
- package/blocks/sequencer/components/enroll-dialog.tsx +2 -2
- package/blocks/sequencer/components/enrollment-withdraw.tsx +71 -0
- package/blocks/sequencer/components/record-sequences-tab.tsx +126 -0
- package/blocks/sequencer/components/sequence-builder.tsx +32 -23
- package/blocks/sequencer/components/sequence-campaign-link.tsx +78 -0
- package/blocks/sequencer/components/sequence-detail.tsx +10 -2
- package/blocks/sequencer/components/sequence-edit-form.tsx +111 -0
- package/blocks/sequencer/components/sequence-enrollments.tsx +5 -2
- package/blocks/sequencer/components/sequence-list.tsx +1 -1
- package/blocks/sequencer/components/sequence-manage-actions.tsx +119 -0
- package/blocks/sequencer/components/sequence-senders-panel.tsx +84 -0
- package/blocks/sequencer/components/sequence-stats.tsx +8 -8
- package/blocks/sequencer/components/sequence-templates.tsx +160 -0
- package/blocks/sequencer/components/sequences-screen.tsx +39 -6
- package/blocks/sequencer/components/step-ai-assist.tsx +196 -0
- package/blocks/sequencer/components/step-editor.tsx +21 -12
- package/blocks/sequencer/components/step-templates.tsx +224 -0
- package/blocks/sequencer/lib/sequencer-manage.ts +235 -0
- package/blocks/sequencer/lib/sequencer-utils.ts +9 -5
- package/blocks/signals/README.md +39 -0
- package/blocks/signals/block.json +287 -0
- package/blocks/signals/components/auto-seed-panel.tsx +111 -0
- package/blocks/signals/components/listener-form.tsx +184 -0
- package/blocks/signals/components/matched-posts.tsx +195 -0
- package/blocks/signals/components/post-engagements.tsx +114 -0
- package/blocks/signals/components/record-social-tab.tsx +49 -0
- package/blocks/signals/components/social-listeners-screen.tsx +250 -0
- package/blocks/signals/components/social-settings.tsx +128 -0
- package/blocks/signals/components/source-lists.tsx +83 -0
- package/blocks/signals/components/top-engagers.tsx +68 -0
- package/blocks/signals/components/x-integration.tsx +129 -0
- package/blocks/signals/lib/signals-types.ts +228 -0
- package/blocks/signals/recipes/preview-and-create-a-listener.ts +16 -0
- package/blocks/signals/recipes/spend-against-caps.ts +14 -0
- package/blocks/signals/recipes/triage-matched-posts.ts +18 -0
- package/blocks/social-ads/README.md +8 -0
- package/blocks/social-ads/block.json +137 -4
- package/blocks/social-ads/components/audience-sync-detail.tsx +9 -3
- package/blocks/social-ads/components/audience-sync.tsx +6 -2
- package/blocks/social-ads/components/campaign-ads.tsx +166 -0
- package/blocks/social-ads/components/campaign-detail.tsx +6 -1
- 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 +6 -1
- package/blocks/social-ads/components/creative-gallery.tsx +20 -2
- 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 +4 -2
- package/blocks/social-ads/components/post-detail.tsx +3 -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-screen.tsx +33 -6
- 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/components/snippet-install.tsx +18 -9
- package/blocks/visitors/components/traffic-chart.tsx +7 -6
- package/blocks/visitors/components/visitor-company-card.tsx +24 -14
- package/blocks/visitors/components/visitor-feed.tsx +5 -5
- package/blocks/web-analytics/README.md +102 -0
- package/blocks/web-analytics/block.json +292 -0
- package/blocks/web-analytics/components/acquisition-tab.tsx +154 -0
- package/blocks/web-analytics/components/analytics-filters.tsx +161 -0
- package/blocks/web-analytics/components/audience-tab.tsx +135 -0
- package/blocks/web-analytics/components/conversions-tab.tsx +128 -0
- package/blocks/web-analytics/components/engagement-tab.tsx +123 -0
- package/blocks/web-analytics/components/overview-tab.tsx +102 -0
- package/blocks/web-analytics/components/pages-tab.tsx +148 -0
- package/blocks/web-analytics/components/ranked-table.tsx +103 -0
- package/blocks/web-analytics/components/realtime-tab.tsx +103 -0
- package/blocks/web-analytics/components/report-card.tsx +71 -0
- package/blocks/web-analytics/components/web-analytics-screen.tsx +90 -0
- package/blocks/web-analytics/hooks/use-report.ts +48 -0
- package/blocks/web-analytics/lib/analytics-scope.ts +155 -0
- package/blocks/web-analytics/lib/page-path.ts +14 -0
- package/blocks/web-analytics/lib/web-analytics-types.ts +187 -0
- package/blocks/web-analytics/recipes/best-landing-pages.ts +26 -0
- package/blocks/web-analytics/recipes/form-conversion-check.ts +19 -0
- package/blocks/web-analytics/recipes/weekly-traffic-report.ts +37 -0
- package/blocks/webchat/components/chat-widget-config.tsx +1 -1
- package/blocks/webchat/components/conversation-list.tsx +1 -1
- package/blocks/workbench/README.md +54 -2
- package/blocks/workbench/block.json +234 -5
- package/blocks/workbench/components/column-recipe-editor.tsx +1 -1
- package/blocks/workbench/components/run-progress.tsx +1 -1
- package/blocks/workbench/components/workbench-auto-enrich.tsx +88 -0
- package/blocks/workbench/components/workbench-automation.tsx +36 -0
- package/blocks/workbench/components/workbench-connections.tsx +136 -0
- package/blocks/workbench/components/workbench-crm-import.tsx +91 -0
- package/blocks/workbench/components/workbench-datafile-import.tsx +154 -0
- package/blocks/workbench/components/workbench-grid.tsx +71 -8
- package/blocks/workbench/components/workbench-pipelines.tsx +173 -0
- package/blocks/workbench/components/workbench-row-actions.tsx +8 -1
- package/blocks/workbench/components/workbench-schedule.tsx +191 -0
- package/blocks/workbench/components/workbench-screen.tsx +65 -22
- package/blocks/workbench/components/workbench-send-to-sequence.tsx +116 -0
- package/blocks/workbench/components/workbench-table-list.tsx +14 -2
- package/blocks/workbench/components/workbench-table-settings.tsx +53 -0
- package/blocks/workbench/components/workbench-triggers.tsx +178 -0
- package/blocks/workbench/hooks/use-connected-crms.ts +29 -0
- package/blocks/workbench/lib/api-status.ts +8 -0
- package/blocks/workbench/lib/automation-types.ts +257 -0
- package/blocks/workflows/components/workflow-editor.tsx +1 -1
- package/dist/cli.js +744 -394
- package/dist/index.browser.js +1 -1
- package/dist/index.browser.js.map +1 -1
- package/dist/index.browser.mjs +1 -1
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/react.browser.js +1 -1
- package/dist/react.browser.js.map +1 -1
- package/dist/react.browser.mjs +1 -1
- package/dist/react.browser.mjs.map +1 -1
- package/dist/react.d.mts +2 -2
- package/dist/react.d.ts +2 -2
- package/dist/react.js +1 -1
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +1 -1
- package/dist/react.mjs.map +1 -1
- package/dist/types/blocks/auth.d.ts +45 -0
- package/dist/types/blocks/brand.d.ts +11 -2
- package/dist/types/blocks/create.d.ts +11 -4
- package/dist/types/blocks/doctor.d.ts +1 -0
- package/dist/types/blocks/flows.d.ts +7 -1
- package/dist/types/blocks/orgBrand.d.ts +34 -0
- package/dist/types/cli.d.ts +3 -0
- package/dist/types/version.d.ts +2 -2
- package/docs/api/desk.d.ts +2 -2
- package/docs/api/desk.md +3 -3
- package/docs/api/forms.md +1 -1
- package/package.json +1 -1
- package/stacks/6sense/pages/companies.tsx.tmpl +21 -0
- package/stacks/6sense/pages/contacts.tsx.tmpl +21 -0
- package/stacks/6sense/pages/tasks.tsx.tmpl +19 -0
- package/stacks/6sense.json +37 -4
- package/stacks/apollo/pages/calls.tsx.tmpl +23 -0
- package/stacks/apollo/pages/campaigns.tsx.tmpl +27 -0
- package/stacks/apollo/pages/companies.tsx.tmpl +19 -36
- package/stacks/apollo/pages/contacts.tsx.tmpl +35 -95
- 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 +24 -0
- package/stacks/apollo/pages/meetings.tsx.tmpl +13 -0
- package/stacks/apollo/pages/sequences.tsx.tmpl +18 -0
- package/stacks/apollo/pages/tasks.tsx.tmpl +20 -0
- package/stacks/apollo.json +68 -9
- 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 +8 -4
- package/stacks/clay/pages/companies.tsx.tmpl +17 -1
- package/stacks/clay/pages/contacts.tsx.tmpl +14 -0
- package/stacks/clay/pages/lists.tsx.tmpl +24 -0
- package/stacks/clay/pages/tasks.tsx.tmpl +19 -0
- package/stacks/clay.json +16 -3
- 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 +34 -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 +23 -6
- package/stacks/hootsuite/pages/companies.tsx.tmpl +22 -0
- package/stacks/hootsuite/pages/contacts.tsx.tmpl +30 -0
- package/stacks/hootsuite/pages/lists.tsx.tmpl +12 -0
- package/stacks/hootsuite/pages/tasks.tsx.tmpl +19 -0
- package/stacks/hootsuite.json +19 -4
- package/stacks/hubspot/pages/campaigns.tsx.tmpl +30 -0
- package/stacks/hubspot/pages/companies.tsx.tmpl +16 -35
- package/stacks/hubspot/pages/contacts.tsx.tmpl +35 -95
- package/stacks/hubspot/pages/deals.tsx.tmpl +14 -1
- package/stacks/hubspot/pages/forms.tsx.tmpl +36 -0
- package/stacks/hubspot/pages/inbox.tsx.tmpl +12 -1
- 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/sequences.tsx.tmpl +18 -0
- package/stacks/hubspot/pages/tasks.tsx.tmpl +20 -0
- package/stacks/hubspot/pages/web-analytics.tsx.tmpl +14 -0
- package/stacks/hubspot.json +66 -7
- 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 +18 -4
- package/stacks/mailchimp/pages/companies.tsx.tmpl +22 -0
- package/stacks/mailchimp/pages/contacts.tsx.tmpl +30 -0
- package/stacks/mailchimp/pages/forms.tsx.tmpl +36 -0
- package/stacks/mailchimp/pages/lists.tsx.tmpl +12 -0
- package/stacks/mailchimp/pages/tasks.tsx.tmpl +19 -0
- package/stacks/mailchimp.json +22 -6
- package/stacks/outreach/pages/calls.tsx.tmpl +23 -0
- package/stacks/outreach/pages/campaigns.tsx.tmpl +27 -0
- package/stacks/outreach/pages/companies.tsx.tmpl +22 -0
- package/stacks/outreach/pages/contacts.tsx.tmpl +29 -66
- 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 +18 -0
- package/stacks/outreach/pages/tasks.tsx.tmpl +19 -0
- package/stacks/outreach.json +38 -9
- package/stacks/pipedrive/pages/companies.tsx.tmpl +11 -35
- package/stacks/pipedrive/pages/contacts.tsx.tmpl +17 -35
- package/stacks/pipedrive/pages/deals.tsx.tmpl +10 -1
- package/stacks/pipedrive/pages/inbox.tsx.tmpl +12 -1
- package/stacks/pipedrive/pages/meetings.tsx.tmpl +13 -0
- package/stacks/pipedrive/pages/tasks.tsx.tmpl +20 -0
- package/stacks/pipedrive.json +14 -2
- package/stacks/salesforce/pages/companies.tsx.tmpl +16 -35
- package/stacks/salesforce/pages/contacts.tsx.tmpl +26 -35
- package/stacks/salesforce/pages/deals.tsx.tmpl +14 -1
- package/stacks/salesforce/pages/lifecycle.tsx.tmpl +23 -0
- package/stacks/salesforce/pages/lists.tsx.tmpl +12 -0
- package/stacks/salesforce/pages/tasks.tsx.tmpl +20 -0
- package/stacks/salesforce.json +17 -3
- package/stacks/zoominfo/pages/companies.tsx.tmpl +17 -1
- package/stacks/zoominfo/pages/contacts.tsx.tmpl +16 -0
- package/stacks/zoominfo/pages/lists.tsx.tmpl +24 -0
- package/stacks/zoominfo/pages/tasks.tsx.tmpl +19 -0
- package/stacks/zoominfo.json +36 -3
- package/styles/styles.css +1 -1
- package/templates/auth/auth-route.ts.tmpl +16 -0
- package/templates/auth/g8.auth.anonymous.ts.tmpl +15 -0
- package/templates/auth/g8.auth.basic.ts.tmpl +17 -0
- package/templates/auth/g8.auth.jwt.ts.tmpl +23 -0
- package/templates/auth/g8.auth.password.ts.tmpl +18 -0
- package/templates/auth/g8.auth.session.ts.tmpl +23 -0
- package/templates/auth/middleware.ts.tmpl +14 -0
- package/templates/next-app/README.md.tmpl +5 -0
- package/templates/next-app/app/globals.css.tmpl +349 -64
- package/templates/next-app/components/app-shell.tsx.tmpl +6 -0
- package/templates/next-app/components/shell/quick-jump.tsx.tmpl +4 -0
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* VerifyEmailButton: verify the work emails of a selection. Counts what it will charge for, shows that count and cost
|
|
5
|
+
* in ConfirmSpendDialog, and sends exactly that set.
|
|
6
|
+
*
|
|
7
|
+
* SDK operations, behind ConfirmSpendDialog (billable, scope enrichment:run):
|
|
8
|
+
* 1. verifyContactEmails POST /contacts/verify-email { contact_pks } about 1 credit per verified email
|
|
9
|
+
* Only contacts with a real (not locked, not empty) work email are counted and sent: the "***" placeholder is never
|
|
10
|
+
* sent. Already verified emails come back as `already_verified` and inconclusive checks are not stored or
|
|
11
|
+
* charged; the result line states what was charged (`charged_credits`) rather than the estimate. At most 1000.
|
|
12
|
+
*
|
|
13
|
+
* The confirm is disabled while its request runs, and a failed call keeps the selection so the person can retry.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { useState } from "react";
|
|
17
|
+
import { Button } from "@graph8/sdk/ui";
|
|
18
|
+
import { MailCheck } from "lucide-react";
|
|
19
|
+
import { ApiError } from "@/g8/components/api-error";
|
|
20
|
+
import { ConfirmSpendDialog } from "@/g8/components/confirm-spend-dialog";
|
|
21
|
+
import { useG8Mutation } from "@/g8/hooks/use-g8-mutation";
|
|
22
|
+
import { g8Post } from "@/g8/lib/g8-client";
|
|
23
|
+
import { plural } from "@/g8/lib/plural";
|
|
24
|
+
import type { ContactRecord } from "../lib/crm-types";
|
|
25
|
+
import { MAX_PAID_BATCH, VERIFY_CREDITS_PER_EMAIL, verifySummary, verifyTargets } from "../lib/record-actions";
|
|
26
|
+
import type { VerifyRow } from "../lib/record-actions";
|
|
27
|
+
|
|
28
|
+
export interface PaidActionProps {
|
|
29
|
+
rows: ReadonlyArray<ContactRecord>;
|
|
30
|
+
onDone?: () => void;
|
|
31
|
+
variant?: "default" | "outline" | "secondary" | "ghost";
|
|
32
|
+
size?: "default" | "sm";
|
|
33
|
+
className?: string;
|
|
34
|
+
/** Start with the confirm open and render no trigger (the row actions dialog opens it). */
|
|
35
|
+
defaultOpen?: boolean;
|
|
36
|
+
onClosed?: () => void;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** A list answer that is a bare array or an envelope with the list under a common key. */
|
|
40
|
+
function anyRows<T>(data: unknown): T[] {
|
|
41
|
+
if (Array.isArray(data)) return data as T[];
|
|
42
|
+
const o = data as Record<string, unknown> | null | undefined;
|
|
43
|
+
for (const k of ["items", "results", "contacts", "data"]) if (Array.isArray(o?.[k])) return o![k] as T[];
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function VerifyEmailButton({ rows, onDone, variant = "outline", size = "sm", className, defaultOpen = false, onClosed }: PaidActionProps) {
|
|
48
|
+
const [open, setOpen] = useState(defaultOpen);
|
|
49
|
+
const [summary, setSummary] = useState<string | null>(null);
|
|
50
|
+
// One filter, used for the count, the cost and the request body.
|
|
51
|
+
const targets = verifyTargets(rows);
|
|
52
|
+
const left = rows.length - targets.length;
|
|
53
|
+
|
|
54
|
+
const verify = useG8Mutation(async (ids: number[]) => {
|
|
55
|
+
const res = await g8Post<unknown>("/contacts/verify-email", { contact_pks: ids });
|
|
56
|
+
return anyRows<VerifyRow>(res.data);
|
|
57
|
+
}, {
|
|
58
|
+
invalidates: [["contacts", "list"], ["contacts", "detail"], ["contacts", "record"]],
|
|
59
|
+
onSuccess: (out) => { setOpen(false); setSummary(verifySummary(out)); onDone?.(); onClosed?.(); },
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<>
|
|
64
|
+
{defaultOpen ? null : (
|
|
65
|
+
<Button className={className} variant={variant} size={size} disabled={targets.length === 0} title={targets.length === 0 ? "None of the selected contacts has an unlocked work email" : undefined} onClick={() => { setSummary(null); verify.reset(); setOpen(true); }}>
|
|
66
|
+
<MailCheck className="size-4" aria-hidden />Verify email
|
|
67
|
+
</Button>
|
|
68
|
+
)}
|
|
69
|
+
{summary ? <span role="status" className="text-xs text-muted-foreground">{summary}</span> : null}
|
|
70
|
+
{verify.error && !open ? <ApiError compact error={verify.error} title="Could not verify the emails" /> : null}
|
|
71
|
+
<ConfirmSpendDialog
|
|
72
|
+
open={open}
|
|
73
|
+
tier="billable"
|
|
74
|
+
title={`Verify ${plural(targets.length, "email")}`}
|
|
75
|
+
description={
|
|
76
|
+
<>
|
|
77
|
+
Checks whether each address can receive mail and stores the answer on the contact. Already verified emails and inconclusive checks are not charged.
|
|
78
|
+
{left > 0 ? ` ${plural(left, "selected contact")} ${left === 1 ? "has" : "have"} no unlocked email and ${left === 1 ? "is" : "are"} left out.` : ""}
|
|
79
|
+
{rows.filter((r) => !!r.work_email).length > MAX_PAID_BATCH ? ` Only the first ${MAX_PAID_BATCH.toLocaleString()} are verified in one go.` : ""}
|
|
80
|
+
{verify.error ? <span role="alert" className="mt-2 block text-destructive">The check failed. Nothing was charged for the failed call; you can try again.</span> : null}
|
|
81
|
+
</>
|
|
82
|
+
}
|
|
83
|
+
estimatedCredits={targets.length * VERIFY_CREDITS_PER_EMAIL}
|
|
84
|
+
affected={targets.length}
|
|
85
|
+
confirmLabel="Verify"
|
|
86
|
+
confirming={verify.loading}
|
|
87
|
+
onConfirm={() => void verify.mutate(targets.map((t) => t.id))}
|
|
88
|
+
onCancel={() => { setOpen(false); onClosed?.(); }}
|
|
89
|
+
/>
|
|
90
|
+
</>
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* useAllLists: every list of the workspace, for a screen that must look one up by id (its size, its name). The lists API
|
|
5
|
+
* pages (`page`, `limit`), so this reads page after page (100 each, up to 20 pages) instead of one capped `limit=200`
|
|
6
|
+
* call; `truncated` says the page cap was reached. To CHOOSE a list use ListSelect (searchable, paged).
|
|
7
|
+
*
|
|
8
|
+
* SDK operations: GET /lists?page&limit (lists.listLists) read - through lib/read-lists.ts
|
|
9
|
+
*/
|
|
10
|
+
import { useAllPages } from "@/g8/hooks/use-all-pages";
|
|
11
|
+
import type { ListSelectOption } from "@/g8/components/list-select";
|
|
12
|
+
import { readLists } from "../lib/read-lists";
|
|
13
|
+
|
|
14
|
+
const PAGE = 100;
|
|
15
|
+
|
|
16
|
+
export function useAllLists(deps: readonly unknown[] = [], enabled = true) {
|
|
17
|
+
return useAllPages<ListSelectOption>((page, signal) => readLists("", page, PAGE, signal), deps, { enabled });
|
|
18
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* useContactTags: the org's tag definitions (`GET /contacts/tags`), cached under ["contact-tags"] so every chip row, the
|
|
5
|
+
* assign dialog and the tag manager share one request and refresh together after a write.
|
|
6
|
+
*
|
|
7
|
+
* SDK operations: listContactTags (read). The list is not paged by the API (it answers every tag at once with a
|
|
8
|
+
* contact count), so there is no "first N" to disclose. Archived tags are left out unless asked for.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { useMemo } from "react";
|
|
12
|
+
import { useG8Query } from "@/g8/hooks/use-g8-query";
|
|
13
|
+
import { g8Get } from "@/g8/lib/g8-client";
|
|
14
|
+
import { isArchivedTag, rowsOf } from "../lib/record-actions";
|
|
15
|
+
import type { ContactTag } from "../lib/record-actions";
|
|
16
|
+
|
|
17
|
+
export function useContactTags(options: { enabled?: boolean; includeArchived?: boolean } = {}) {
|
|
18
|
+
const { enabled = true, includeArchived = false } = options;
|
|
19
|
+
const query = useG8Query(
|
|
20
|
+
(signal) => g8Get<unknown>("/contacts/tags", includeArchived ? { include_archived: true } : undefined, { signal }),
|
|
21
|
+
[includeArchived],
|
|
22
|
+
{ enabled, key: ["contact-tags", includeArchived ? "all" : "active"] },
|
|
23
|
+
);
|
|
24
|
+
const tags = useMemo(() => {
|
|
25
|
+
const rows = rowsOf<ContactTag>(query.data?.data, "tags").filter((t) => t && typeof t.id === "string" && t.id !== "");
|
|
26
|
+
return includeArchived ? rows : rows.filter((t) => !isArchivedTag(t));
|
|
27
|
+
}, [query.data, includeArchived]);
|
|
28
|
+
return { tags, loading: query.loading && !query.data, error: query.error, refetch: query.refetch, loaded: query.data != null };
|
|
29
|
+
}
|
|
@@ -34,12 +34,14 @@ export function usePageQuery<T>(
|
|
|
34
34
|
deps: readonly unknown[],
|
|
35
35
|
pageSize = 25,
|
|
36
36
|
cacheKey?: readonly unknown[],
|
|
37
|
+
/** Hold the read (for example until URL filters are known). Default true. */
|
|
38
|
+
enabled = true,
|
|
37
39
|
): UsePageQueryResult<T> {
|
|
38
40
|
const key = JSON.stringify(deps);
|
|
39
41
|
const [state, setState] = useState({ key, page: 1 });
|
|
40
42
|
const page = state.key === key ? state.page : 1;
|
|
41
43
|
const queryKey: G8QueryKey | undefined = cacheKey ? [...cacheKey, { page, pageSize, deps: key }] : undefined;
|
|
42
|
-
const query = useG8Query((signal) => fetchPage(page, signal), [key, page], { key: queryKey });
|
|
44
|
+
const query = useG8Query((signal) => fetchPage(page, signal), [key, page], { key: queryKey, enabled });
|
|
43
45
|
|
|
44
46
|
const info = query.data?.pagination as Partial<PageInfo> | undefined;
|
|
45
47
|
const rows = (query.data?.data ?? []) as T[];
|
|
@@ -31,6 +31,8 @@ export interface ContactRecord {
|
|
|
31
31
|
last_name?: string | null;
|
|
32
32
|
full_name?: string | null;
|
|
33
33
|
work_email?: string | null;
|
|
34
|
+
/** Personal addresses, comma separated. */
|
|
35
|
+
personal_emails?: string | null;
|
|
34
36
|
direct_phone?: string | null;
|
|
35
37
|
mobile_phone?: string | null;
|
|
36
38
|
job_title?: string | null;
|
|
@@ -107,6 +109,18 @@ export function contactName(c: Pick<ContactRecord, "first_name" | "last_name" |
|
|
|
107
109
|
return joined || c.full_name || (c.work_email && !isMasked(c.work_email) ? c.work_email : "") || (c.id != null ? `#${c.id}` : "-");
|
|
108
110
|
}
|
|
109
111
|
|
|
112
|
+
/**
|
|
113
|
+
* The line under a contact's name: "VP of Sales at Acme". The company is the company's own name (`company.name`, else the
|
|
114
|
+
* list row's `company_name`); it never falls back to anything about the person. "at ..." is left out when there is no
|
|
115
|
+
* title or no company. A company that happens to share the person's name (a freelancer) is shown as the API sent it.
|
|
116
|
+
*/
|
|
117
|
+
export function contactSubtitle(c: Pick<ContactRecord, "job_title" | "company_name" | "company">): string {
|
|
118
|
+
const company = [c.company?.name, c.company_name].map((n) => (n ?? "").trim()).find((n) => n !== "");
|
|
119
|
+
const title = (c.job_title ?? "").trim();
|
|
120
|
+
if (title && company) return `${title} at ${company}`;
|
|
121
|
+
return title || company || "No title or company";
|
|
122
|
+
}
|
|
123
|
+
|
|
110
124
|
/** A company's display name: name, then domain, then `#id`, then a dash. Never "Unnamed". */
|
|
111
125
|
export function companyName(c: { name?: string | null; domain?: string | null; id?: number | string }): string {
|
|
112
126
|
return c.name || c.domain || (c.id != null ? `#${c.id}` : "-");
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* readLists: one page of audience lists, for ListSelect and useAllLists.
|
|
5
|
+
*
|
|
6
|
+
* SDK operations: GET /lists?search&page&limit (lists.listLists) read
|
|
7
|
+
*/
|
|
8
|
+
import { g8Get } from "@/g8/lib/g8-client";
|
|
9
|
+
import { hasNextOf } from "@/g8/lib/paging";
|
|
10
|
+
import type { ListSelectOption, ListsReader } from "@/g8/components/list-select";
|
|
11
|
+
|
|
12
|
+
export const readLists: ListsReader = async (q, page, pageSize, signal) => {
|
|
13
|
+
const env = await g8Get<ListSelectOption[]>("/lists", { search: q || undefined, page, limit: pageSize }, { signal });
|
|
14
|
+
const rows = (env.data ?? []) as ListSelectOption[];
|
|
15
|
+
return { rows, hasNext: hasNextOf(env, pageSize, rows.length) };
|
|
16
|
+
};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Shared helpers for the CRM record actions (owner, tags, bulk update, verify, unlock, AI documents, next best step).
|
|
5
|
+
* Pure functions and types only: no operations of its own.
|
|
6
|
+
*
|
|
7
|
+
* Why the sets are computed here: a confirm dialog must COUNT exactly the set the request SENDS (#25642). Every paid
|
|
8
|
+
* action filters its selection once with one of these helpers and uses the SAME array for the count, the cost line
|
|
9
|
+
* and the request body.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { isMasked } from "./crm-types";
|
|
13
|
+
import type { ContactRecord } from "./crm-types";
|
|
14
|
+
|
|
15
|
+
/** One contact tag definition (`GET /contacts/tags`). The handler sends `archived_at`; the contract types `archived`. */
|
|
16
|
+
export interface ContactTag {
|
|
17
|
+
id: string;
|
|
18
|
+
name: string;
|
|
19
|
+
color?: string | null;
|
|
20
|
+
description?: string | null;
|
|
21
|
+
contact_count?: number | null;
|
|
22
|
+
archived?: boolean | null;
|
|
23
|
+
archived_at?: string | null;
|
|
24
|
+
is_default?: boolean | null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function isArchivedTag(tag: ContactTag): boolean {
|
|
28
|
+
return tag.archived === true || (tag.archived_at != null && tag.archived_at !== "");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** The API takes six-digit hex colours only (`^#[0-9A-Fa-f]{6}$`). */
|
|
32
|
+
export const HEX_COLOR = /^#[0-9A-Fa-f]{6}$/;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The tag palette offered in the tag manager. Free choice of a hex colour is also allowed; these are only the
|
|
36
|
+
* one-click choices, so no screen ever shows a raw colour input as its only control.
|
|
37
|
+
*/
|
|
38
|
+
export const TAG_COLORS = ["#2563EB", "#0F766E", "#B45309", "#B91C1C", "#6D28D9", "#475569"] as const;
|
|
39
|
+
|
|
40
|
+
/** `POST /contacts/unlock-info` takes at most 1000 contact ids; `POST /contacts/verify-email` at most 1000 too. */
|
|
41
|
+
export const MAX_PAID_BATCH = 1000;
|
|
42
|
+
|
|
43
|
+
/** One credit per newly unlocked contact (contacts/interfaces/fastapi/router.py: "estimated_credits ... 1 credit per contact"). */
|
|
44
|
+
export const UNLOCK_CREDITS_PER_CONTACT = 1;
|
|
45
|
+
/** One credit per verified email (the same price the enrichment block shows for a single verification). */
|
|
46
|
+
export const VERIFY_CREDITS_PER_EMAIL = 1;
|
|
47
|
+
|
|
48
|
+
/** A contact with any masked email or phone: unlocking reveals it. */
|
|
49
|
+
export function isLockedContact(row: Pick<ContactRecord, "work_email" | "direct_phone" | "mobile_phone">): boolean {
|
|
50
|
+
return isMasked(row.work_email) || isMasked(row.direct_phone) || isMasked(row.mobile_phone);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** The contacts an unlock would charge for: only the locked ones, capped at the API's batch size. */
|
|
54
|
+
export function unlockTargets(rows: ReadonlyArray<ContactRecord>): ContactRecord[] {
|
|
55
|
+
return rows.filter(isLockedContact).slice(0, MAX_PAID_BATCH);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** The contacts with a real work email. A locked or empty email cannot be verified, and the "***" placeholder is never sent. */
|
|
59
|
+
export function verifyTargets(rows: ReadonlyArray<ContactRecord>): ContactRecord[] {
|
|
60
|
+
return rows.filter((r) => !!r.work_email && r.work_email.trim() !== "" && !isMasked(r.work_email)).slice(0, MAX_PAID_BATCH);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Fields the bulk updater offers. Names are the contact's own columns (`bulk-update` only accepts `CONTACT_*` and `udo_*` keys); anything else, including the owner (own action) and tags (own action), is not editable here.
|
|
65
|
+
*/
|
|
66
|
+
export const BULK_FIELDS = [
|
|
67
|
+
{ key: "CONTACT_JOB_TITLE", label: "Job title" },
|
|
68
|
+
{ key: "CONTACT_JOB_DEPARTMENT", label: "Department" },
|
|
69
|
+
{ key: "CONTACT_SENIORITY_LEVEL", label: "Seniority" },
|
|
70
|
+
{ key: "CONTACT_CITY", label: "City" },
|
|
71
|
+
{ key: "CONTACT_STATE", label: "State" },
|
|
72
|
+
{ key: "CONTACT_COUNTRY", label: "Country" },
|
|
73
|
+
] as const;
|
|
74
|
+
export type BulkFieldKey = (typeof BULK_FIELDS)[number]["key"];
|
|
75
|
+
|
|
76
|
+
/** The result rows of a verify call. */
|
|
77
|
+
export interface VerifyRow {
|
|
78
|
+
contact_pk?: number;
|
|
79
|
+
outcome?: "verified" | "already_verified" | "inconclusive" | "not_verified" | null;
|
|
80
|
+
verification_result?: string | null;
|
|
81
|
+
charged_credits?: number;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** "Verified 3, already verified 1, inconclusive 1 (not charged). 3 credits charged." */
|
|
85
|
+
export function verifySummary(rows: ReadonlyArray<VerifyRow>): string {
|
|
86
|
+
const n = (o: string) => rows.filter((r) => r.outcome === o).length;
|
|
87
|
+
const parts = [
|
|
88
|
+
`Verified ${n("verified")}`,
|
|
89
|
+
n("already_verified") ? `already verified ${n("already_verified")}` : "",
|
|
90
|
+
n("inconclusive") ? `inconclusive ${n("inconclusive")} (not charged)` : "",
|
|
91
|
+
n("not_verified") ? `no answer for ${n("not_verified")} (not charged)` : "",
|
|
92
|
+
].filter(Boolean);
|
|
93
|
+
const charged = rows.reduce((max, r) => Math.max(max, r.charged_credits ?? 0), 0);
|
|
94
|
+
return `${parts.join(", ")}. ${charged.toLocaleString()} ${charged === 1 ? "credit" : "credits"} charged.`;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** The array inside an envelope `data` that is either the array itself or `{ <key>: [...] }`. */
|
|
98
|
+
export function rowsOf<T>(data: unknown, key: string): T[] {
|
|
99
|
+
if (Array.isArray(data)) return data as T[];
|
|
100
|
+
const inner = (data as Record<string, unknown> | null | undefined)?.[key];
|
|
101
|
+
return Array.isArray(inner) ? (inner as T[]) : [];
|
|
102
|
+
}
|
package/blocks/deals/README.md
CHANGED
|
@@ -11,19 +11,33 @@ compose under `DealDetail`'s `children`). Drag and drop needs `npm i @dnd-kit/co
|
|
|
11
11
|
|
|
12
12
|
- Board and List views, search by name, a pipeline switcher when there is more than one pipeline.
|
|
13
13
|
- Headline numbers: open deals, open value, estimated weighted value, won value.
|
|
14
|
-
- Open a deal (board card or list row, deep link `?id=<deal id>`): Details (edit, stage history, confirmed delete)
|
|
15
|
-
|
|
14
|
+
- Open a deal (board card or list row, deep link `?id=<deal id>`): Details (edit, stage history, confirmed delete),
|
|
15
|
+
Contacts (add with a role, change a role, make primary, remove), Line items (add, edit, remove, totals), Notes (add,
|
|
16
|
+
edit, delete), Tasks (add, complete), Quotes and Activity tabs. Moving a card into a won or lost stage asks for the
|
|
17
|
+
close date and amount first.
|
|
18
|
+
- **Close deal** (detail header): won or lost, with a close date, an amount for won, and a reason picked from the org's
|
|
19
|
+
close reasons (add one on the spot). **API gap:** no deal operation accepts a close reason (`closed_lost_reason` is
|
|
20
|
+
read only), so the reason is saved as a deal note, "Closed lost. Reason: Price". **Move to pipeline** is next to it.
|
|
21
|
+
- Filters on Board and List: owner, stage, outcome (open, won, lost), stale (no activity for 7 to 90 days, or never),
|
|
22
|
+
activity, close-date range and "no contact". `filterQuery(state)` turns them into the `GET /deals` parameters.
|
|
23
|
+
- Pipeline settings: create, rename, make default and delete (confirmed) pipelines, add or archive close reasons,
|
|
24
|
+
then the stage summary and StageEditor.
|
|
25
|
+
- Quotes tab: the deal's quotes. To offer "Create quote from this deal", pass the quotes block's button:
|
|
26
|
+
`<DealsScreen renderQuoteActions={(deal) => <CreateQuoteFromDeal dealId={deal.id} />} />` (quotes depends on deals,
|
|
27
|
+
so the deals block cannot import it).
|
|
16
28
|
- **New deal**: name, amount, close date, stage, an **owner** and **at least one contact**. The API requires both
|
|
17
29
|
(`owner_id`, and `contact_ids` with one or more mashup contact ids that all work at one company; the older note that
|
|
18
30
|
the list may be empty was wrong). A company that already has a deal is refused with 409 unless "Allow another deal"
|
|
19
31
|
is ticked.
|
|
20
|
-
- Forecast tab (totals, win rate, stuck deals, estimated weighted pipeline) and Pipeline settings tab (
|
|
21
|
-
probabilities, won/lost types, order, delete).
|
|
32
|
+
- Forecast tab (totals, win rate, stuck deals, estimated weighted pipeline) and Pipeline settings tab (pipelines, close
|
|
33
|
+
reasons, stage names, probabilities, won/lost types, order, delete).
|
|
22
34
|
- Slots for cross-block glue, all optional: `renderRowActions(deal)`, `renderDetailActions(deal)`,
|
|
23
35
|
`extraDetailTabs`, `toolbarActions`. Example: add a Quotes tab with `<QuoteList dealId={deal.id} />`.
|
|
24
36
|
|
|
25
|
-
Scopes the screen needs on top of the lists below: `team:read` (owner default and picker)
|
|
26
|
-
(contact search)
|
|
37
|
+
Scopes the screen needs on top of the lists below: `team:read` (owner default and picker), `contacts:read`
|
|
38
|
+
(contact search), `notes:read` and `notes:write` (Notes tab), `tasks:read` and `tasks:write` (Tasks tab) and
|
|
39
|
+
`deals:delete` (remove a contact, delete a note, archive a close reason).
|
|
40
|
+
Proxy `allowedPrefixes` must include `deals`, `pipelines`, `team-members`, `contacts`, `tasks` (and `activity`
|
|
27
41
|
for the timeline).
|
|
28
42
|
|
|
29
43
|
|
|
@@ -107,3 +121,8 @@ create), `deal.id` + `deal.revision` (card -> detail -> update/delete).
|
|
|
107
121
|
- `01-create-deal-and-advance.ts`: create, move, close as won.
|
|
108
122
|
- `02-pipeline-report.ts`: totals, win rate, stall points, estimated weighted forecast.
|
|
109
123
|
- `03-stale-deals-sweep.ts`: find neglected open deals, optionally flag them with one bulk write.
|
|
124
|
+
|
|
125
|
+
## Cross-block glue
|
|
126
|
+
|
|
127
|
+
- `RecordDealsTab` (`components/record-deals-tab.tsx`): the deals of one contact or company (`GET /contacts/{id}/deals`, `GET /companies/{id}/deals`), each opening in the deals screen. Use it as an `extraDetailTabs` entry of `ContactsScreen` / `CompaniesScreen`. `DealsScreen` also takes optional `onOpenContact` / `onOpenCompany`: the Contacts tab gains "Open in contacts" and the contact sheet gains "Open company".
|
|
128
|
+
- `CreateDealButton` (`components/create-deal-button.tsx`): "Create deal" for one contact. A sheet with the deal form already filled in from the contact and their company (linked contact, name "<company> - <contact>", owner from the key's person or a picker). `onCreated(dealId)` routes to the new deal. The company comes from the contact (the API derives it), and a company that already has a deal is refused until "Create another deal for this company" is ticked. Use it in `ContactsScreen.renderDetailActions`.
|
package/blocks/deals/block.json
CHANGED
|
@@ -8,30 +8,57 @@
|
|
|
8
8
|
"optimistic stage moves with rollback and closed-stage rules handled",
|
|
9
9
|
"deal create, edit, stage history and confirmed delete",
|
|
10
10
|
"stage editor: names, probabilities, won/lost types, order",
|
|
11
|
-
"forecast: totals, win rate, stuck deals and an estimated weighted pipeline"
|
|
11
|
+
"forecast: totals, win rate, stuck deals and an estimated weighted pipeline",
|
|
12
|
+
"deal notes, tasks, contacts with roles and primary, and line items with totals",
|
|
13
|
+
"close a deal as won or lost with a reason",
|
|
14
|
+
"create, rename, default and delete pipelines, and manage close reasons",
|
|
15
|
+
"list filters: owner, stage, outcome, stale, activity, close-date range, no contact"
|
|
12
16
|
],
|
|
13
17
|
"dependsOn": [
|
|
14
18
|
"crm"
|
|
15
19
|
],
|
|
16
20
|
"operations": [
|
|
21
|
+
"add_deal_contact_deals__deal_id__contacts_post",
|
|
22
|
+
"archive_deal_close_reason_deals_close_reasons__reason_id__delete",
|
|
23
|
+
"create_deal_close_reason_deals_close_reasons_post",
|
|
17
24
|
"create_deal_deals_post",
|
|
25
|
+
"create_deal_note_deals__deal_id__notes_post",
|
|
26
|
+
"create_global_task_tasks_post",
|
|
27
|
+
"create_pipeline_pipelines_post",
|
|
18
28
|
"create_stage_pipelines__pipeline_id__stages_post",
|
|
19
29
|
"delete_deal_deals__deal_id__delete",
|
|
30
|
+
"delete_deal_note_deals__deal_id__notes__note_id__delete",
|
|
31
|
+
"delete_pipeline_pipelines__pipeline_id__delete",
|
|
20
32
|
"delete_stage_pipelines__pipeline_id__stages__stage_id__delete",
|
|
33
|
+
"get_company_deals_companies__company_id__deals_get",
|
|
34
|
+
"get_contact_contacts__contact_id__get",
|
|
35
|
+
"get_contact_deals_contacts__contact_id__deals_get",
|
|
21
36
|
"get_deal_analytics_deals_analytics_get",
|
|
22
37
|
"get_deal_deals__deal_id__get",
|
|
23
38
|
"get_deal_stage_velocity_deals_stage_velocity_get",
|
|
24
39
|
"get_my_team_member_team_members_me_get",
|
|
25
40
|
"get_pipeline_pipelines__pipeline_id__get",
|
|
41
|
+
"list_all_tasks_tasks_get",
|
|
26
42
|
"list_contacts_contacts_get",
|
|
43
|
+
"list_deal_close_reasons_deals_close_reasons_get",
|
|
27
44
|
"list_deal_history_deals__deal_id__history_get",
|
|
45
|
+
"list_deal_line_items_deals__deal_id__line_items_get",
|
|
46
|
+
"list_deal_notes_deals__deal_id__notes_get",
|
|
28
47
|
"list_deals_deals_get",
|
|
29
48
|
"list_pipelines_deals_pipelines_get",
|
|
30
49
|
"list_quotes_quotes_get",
|
|
31
50
|
"list_team_members_team_members_get",
|
|
51
|
+
"move_deal_to_pipeline_deals__deal_id__pipeline_put",
|
|
52
|
+
"remove_deal_contact_deals__deal_id__contacts__person_id__delete",
|
|
32
53
|
"reorder_stages_pipelines__pipeline_id__stages_reorder_put",
|
|
54
|
+
"replace_deal_line_items_deals__deal_id__line_items_put",
|
|
55
|
+
"set_deal_contact_role_deals__deal_id__contacts__contact_id__put",
|
|
56
|
+
"set_primary_deal_contact_deals__deal_id__contacts__person_id__primary_put",
|
|
33
57
|
"update_deal_deals__deal_id__patch",
|
|
34
|
-
"
|
|
58
|
+
"update_deal_note_deals__deal_id__notes__note_id__put",
|
|
59
|
+
"update_pipeline_pipelines__pipeline_id__put",
|
|
60
|
+
"update_stage_pipelines__pipeline_id__stages__stage_id__put",
|
|
61
|
+
"update_task_tasks__task_id__patch"
|
|
35
62
|
],
|
|
36
63
|
"components": [
|
|
37
64
|
{
|
|
@@ -120,6 +147,137 @@
|
|
|
120
147
|
"tiers": [
|
|
121
148
|
"read"
|
|
122
149
|
]
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
"name": "DealNotesTab",
|
|
153
|
+
"file": "components/deal-notes-tab.tsx",
|
|
154
|
+
"purpose": "Notes of one deal: list, add, edit (only when the text changed) and confirmed delete; synced notes are read only.",
|
|
155
|
+
"operations": [
|
|
156
|
+
"create_deal_note_deals__deal_id__notes_post",
|
|
157
|
+
"delete_deal_note_deals__deal_id__notes__note_id__delete",
|
|
158
|
+
"list_deal_notes_deals__deal_id__notes_get",
|
|
159
|
+
"update_deal_note_deals__deal_id__notes__note_id__put"
|
|
160
|
+
],
|
|
161
|
+
"tiers": [
|
|
162
|
+
"read",
|
|
163
|
+
"write",
|
|
164
|
+
"destructive"
|
|
165
|
+
]
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
"name": "DealTasksTab",
|
|
169
|
+
"file": "components/deal-tasks-tab.tsx",
|
|
170
|
+
"purpose": "Follow-up tasks linked to one deal: list (open or all), add with due date and priority, complete and reopen.",
|
|
171
|
+
"operations": [
|
|
172
|
+
"create_global_task_tasks_post",
|
|
173
|
+
"list_all_tasks_tasks_get",
|
|
174
|
+
"update_task_tasks__task_id__patch"
|
|
175
|
+
],
|
|
176
|
+
"tiers": [
|
|
177
|
+
"read",
|
|
178
|
+
"write"
|
|
179
|
+
]
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
"name": "DealContactsEditor",
|
|
183
|
+
"file": "components/deal-contacts-editor.tsx",
|
|
184
|
+
"purpose": "Buying committee of one deal: add a contact with a role, change a role, make one primary, remove one (confirmed).",
|
|
185
|
+
"operations": [
|
|
186
|
+
"add_deal_contact_deals__deal_id__contacts_post",
|
|
187
|
+
"get_deal_deals__deal_id__get",
|
|
188
|
+
"list_contacts_contacts_get",
|
|
189
|
+
"remove_deal_contact_deals__deal_id__contacts__person_id__delete",
|
|
190
|
+
"set_deal_contact_role_deals__deal_id__contacts__contact_id__put",
|
|
191
|
+
"set_primary_deal_contact_deals__deal_id__contacts__person_id__primary_put"
|
|
192
|
+
],
|
|
193
|
+
"tiers": [
|
|
194
|
+
"read",
|
|
195
|
+
"write",
|
|
196
|
+
"destructive"
|
|
197
|
+
]
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
"name": "DealLineItems",
|
|
201
|
+
"file": "components/deal-line-items.tsx",
|
|
202
|
+
"purpose": "Products on a deal: add, edit and remove lines (dollars in, cents sent), per-line totals, the deal total and the quote-mismatch warning.",
|
|
203
|
+
"operations": [
|
|
204
|
+
"list_deal_line_items_deals__deal_id__line_items_get",
|
|
205
|
+
"replace_deal_line_items_deals__deal_id__line_items_put"
|
|
206
|
+
],
|
|
207
|
+
"tiers": [
|
|
208
|
+
"read",
|
|
209
|
+
"write"
|
|
210
|
+
]
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
"name": "DealActions",
|
|
214
|
+
"file": "components/close-deal-dialog.tsx",
|
|
215
|
+
"purpose": "Deal header actions: Close deal as won or lost with a reason (saved as a note, the API has no reason field), add close reasons, and Move to pipeline. CloseDealDialog is the dialog alone.",
|
|
216
|
+
"operations": [
|
|
217
|
+
"create_deal_close_reason_deals_close_reasons_post",
|
|
218
|
+
"create_deal_note_deals__deal_id__notes_post",
|
|
219
|
+
"list_deal_close_reasons_deals_close_reasons_get",
|
|
220
|
+
"move_deal_to_pipeline_deals__deal_id__pipeline_put",
|
|
221
|
+
"update_deal_deals__deal_id__patch"
|
|
222
|
+
],
|
|
223
|
+
"tiers": [
|
|
224
|
+
"read",
|
|
225
|
+
"write"
|
|
226
|
+
]
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
"name": "PipelineEditor",
|
|
230
|
+
"file": "components/pipeline-editor.tsx",
|
|
231
|
+
"purpose": "Create, rename, make default and delete (confirmed) pipelines, and add or archive (confirmed) close reasons. Stages are edited by StageEditor.",
|
|
232
|
+
"operations": [
|
|
233
|
+
"archive_deal_close_reason_deals_close_reasons__reason_id__delete",
|
|
234
|
+
"create_deal_close_reason_deals_close_reasons_post",
|
|
235
|
+
"create_pipeline_pipelines_post",
|
|
236
|
+
"delete_pipeline_pipelines__pipeline_id__delete",
|
|
237
|
+
"list_deal_close_reasons_deals_close_reasons_get",
|
|
238
|
+
"list_pipelines_deals_pipelines_get",
|
|
239
|
+
"update_pipeline_pipelines__pipeline_id__put"
|
|
240
|
+
],
|
|
241
|
+
"tiers": [
|
|
242
|
+
"read",
|
|
243
|
+
"write",
|
|
244
|
+
"destructive"
|
|
245
|
+
]
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
"name": "DealFilterBar",
|
|
249
|
+
"file": "components/deal-filters.tsx",
|
|
250
|
+
"purpose": "List filters: owner, stage, outcome, stale (7 to 90 days), activity, close-date range and no contact. Pass filterQuery(state) to usePipelineDeals.",
|
|
251
|
+
"operations": [],
|
|
252
|
+
"tiers": []
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
"name": "RecordDealsTab",
|
|
256
|
+
"file": "components/record-deals-tab.tsx",
|
|
257
|
+
"purpose": "The deals linked to one contact or company, each opening in the deals screen; an extraDetailTabs entry for ContactsScreen and CompaniesScreen.",
|
|
258
|
+
"operations": [
|
|
259
|
+
"get_contact_deals_contacts__contact_id__deals_get",
|
|
260
|
+
"get_company_deals_companies__company_id__deals_get"
|
|
261
|
+
],
|
|
262
|
+
"tiers": [
|
|
263
|
+
"read"
|
|
264
|
+
]
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
"name": "CreateDealButton",
|
|
268
|
+
"file": "components/create-deal-button.tsx",
|
|
269
|
+
"purpose": "\"Create deal\" for one contact: a sheet with the deal form prefilled from the contact and their company (linked contact, name \"<company> - <contact>\", owner, pipeline stage). Calls onCreated(dealId) so you can route to the new deal.",
|
|
270
|
+
"operations": [
|
|
271
|
+
"create_deal_deals_post",
|
|
272
|
+
"get_contact_contacts__contact_id__get",
|
|
273
|
+
"get_my_team_member_team_members_me_get",
|
|
274
|
+
"list_pipelines_deals_pipelines_get",
|
|
275
|
+
"list_team_members_team_members_get"
|
|
276
|
+
],
|
|
277
|
+
"tiers": [
|
|
278
|
+
"read",
|
|
279
|
+
"write"
|
|
280
|
+
]
|
|
123
281
|
}
|
|
124
282
|
],
|
|
125
283
|
"hooks": [
|
|
@@ -154,6 +312,10 @@
|
|
|
154
312
|
{
|
|
155
313
|
"file": "lib/deals-types.ts",
|
|
156
314
|
"purpose": "Deal, pipeline and stage types, stage kind, money formatting, weighted-pipeline estimate and closed-stage error markers."
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
"file": "lib/deal-extras.ts",
|
|
318
|
+
"purpose": "Note, task, line-item and close-reason shapes, contact roles, money in cents, and the deal filter state with its GET /deals query."
|
|
157
319
|
}
|
|
158
320
|
],
|
|
159
321
|
"recipes": [
|
|
@@ -201,7 +363,11 @@
|
|
|
201
363
|
"deals:delete",
|
|
202
364
|
"deals:read",
|
|
203
365
|
"deals:write",
|
|
366
|
+
"notes:read",
|
|
367
|
+
"notes:write",
|
|
204
368
|
"quotes:read",
|
|
369
|
+
"tasks:read",
|
|
370
|
+
"tasks:write",
|
|
205
371
|
"team:read"
|
|
206
372
|
],
|
|
207
373
|
"defaults": [
|