@graph8/sdk 0.370.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 +19 -0
- package/blocks/_foundation/README.md +14 -0
- package/blocks/_foundation/block.json +44 -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/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/components/campaign-assets.tsx +1 -1
- package/blocks/campaigns/components/campaign-launch-step.tsx +16 -11
- 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 +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/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 +6 -0
- package/blocks/crm/block.json +53 -4
- 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-lookup-link.tsx +44 -0
- package/blocks/crm/components/contacts-screen.tsx +31 -13
- 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/record-engagement-tab.tsx +103 -0
- package/blocks/crm/components/record-form.tsx +1 -1
- package/blocks/crm/components/tasks-screen.tsx +35 -15
- package/blocks/crm/hooks/use-all-lists.ts +18 -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/deals/README.md +24 -6
- package/blocks/deals/block.json +151 -2
- 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 +2 -2
- 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 +4 -1
- 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/enrichment/README.md +16 -6
- package/blocks/enrichment/block.json +19 -7
- package/blocks/enrichment/components/bulk-enrich-panel.tsx +76 -27
- package/blocks/enrichment/components/email-verify-badge.tsx +3 -3
- package/blocks/enrichment/components/enrich-button.tsx +1 -1
- package/blocks/enrichment/components/enrichment-screen.tsx +70 -17
- package/blocks/enrichment/components/waterfall-config.tsx +27 -7
- package/blocks/enrichment/lib/enrichment-types.ts +39 -0
- package/blocks/enrichment/recipes/bulk-enrich-and-poll.ts +15 -4
- package/blocks/forms/README.md +8 -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 +51 -17
- 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 +5 -0
- package/blocks/inbox/block.json +15 -0
- package/blocks/inbox/components/record-conversations-tab.tsx +154 -0
- package/blocks/inbox/components/thread-badge.tsx +2 -2
- package/blocks/inbox/components/thread-view.tsx +1 -1
- 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 +36 -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 +113 -1
- 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/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 +48 -1
- package/blocks/quotes/components/create-quote-from-deal.tsx +48 -0
- 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 +3 -2
- package/blocks/quotes/components/quote-viewer.tsx +7 -2
- package/blocks/quotes/components/record-quotes-tab.tsx +90 -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 +6 -0
- package/blocks/sequencer/block.json +28 -1
- package/blocks/sequencer/components/add-to-sequence-button.tsx +82 -0
- package/blocks/sequencer/components/enroll-dialog.tsx +2 -2
- package/blocks/sequencer/components/record-sequences-tab.tsx +126 -0
- package/blocks/sequencer/components/sequence-builder.tsx +19 -20
- package/blocks/sequencer/components/sequence-detail.tsx +4 -2
- package/blocks/sequencer/components/sequence-enrollments.tsx +4 -2
- package/blocks/sequencer/components/sequence-list.tsx +1 -1
- package/blocks/sequencer/components/sequence-stats.tsx +8 -8
- package/blocks/sequencer/components/sequences-screen.tsx +3 -0
- package/blocks/sequencer/components/step-editor.tsx +11 -11
- package/blocks/sequencer/lib/sequencer-utils.ts +5 -5
- 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 +4 -4
- package/blocks/visitors/components/visitor-company-card.tsx +24 -14
- package/blocks/visitors/components/visitor-feed.tsx +5 -5
- package/blocks/webchat/components/chat-widget-config.tsx +1 -1
- package/blocks/webchat/components/conversation-list.tsx +1 -1
- package/blocks/workbench/components/column-recipe-editor.tsx +1 -1
- package/blocks/workbench/components/run-progress.tsx +1 -1
- package/blocks/workbench/components/workbench-grid.tsx +1 -1
- package/blocks/workbench/components/workbench-screen.tsx +15 -5
- package/blocks/workbench/components/workbench-table-list.tsx +14 -2
- package/blocks/workflows/components/workflow-editor.tsx +1 -1
- package/dist/cli.js +536 -392
- 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/brand.d.ts +11 -2
- package/dist/types/blocks/create.d.ts +7 -3
- 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/package.json +1 -1
- 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 +17 -4
- package/stacks/apollo/pages/calls.tsx.tmpl +23 -0
- package/stacks/apollo/pages/companies.tsx.tmpl +19 -36
- package/stacks/apollo/pages/contacts.tsx.tmpl +29 -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 +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 +36 -8
- 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 +12 -0
- package/stacks/clay/pages/lists.tsx.tmpl +12 -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 +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 +23 -6
- 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 +9 -4
- package/stacks/hubspot/pages/companies.tsx.tmpl +14 -35
- package/stacks/hubspot/pages/contacts.tsx.tmpl +29 -95
- package/stacks/hubspot/pages/deals.tsx.tmpl +10 -1
- 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 +12 -0
- package/stacks/hubspot/pages/tasks.tsx.tmpl +20 -0
- package/stacks/hubspot.json +21 -5
- 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 +8 -4
- 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 +20 -5
- 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 +27 -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 +12 -0
- package/stacks/outreach/pages/tasks.tsx.tmpl +19 -0
- package/stacks/outreach.json +25 -7
- package/stacks/pipedrive/pages/companies.tsx.tmpl +11 -35
- package/stacks/pipedrive/pages/contacts.tsx.tmpl +15 -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 +4 -2
- package/stacks/salesforce/pages/companies.tsx.tmpl +14 -35
- package/stacks/salesforce/pages/contacts.tsx.tmpl +20 -35
- package/stacks/salesforce/pages/deals.tsx.tmpl +10 -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 +7 -3
- package/stacks/zoominfo/pages/companies.tsx.tmpl +17 -1
- package/stacks/zoominfo/pages/contacts.tsx.tmpl +12 -0
- package/stacks/zoominfo/pages/lists.tsx.tmpl +12 -0
- package/stacks/zoominfo/pages/tasks.tsx.tmpl +19 -0
- package/stacks/zoominfo.json +16 -3
- package/styles/styles.css +1 -1
- 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
|
@@ -34,7 +34,7 @@ export interface CallScorecardProps {
|
|
|
34
34
|
className?: string;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
const VERDICT_STYLE: Record<string, string> = { met: "text-
|
|
37
|
+
const VERDICT_STYLE: Record<string, string> = { met: "text-positive-foreground", partial: "text-warning-foreground", missed: "text-destructive" };
|
|
38
38
|
|
|
39
39
|
export function CallScorecard({ callId, onDeleted, allowDelete = true, className }: CallScorecardProps) {
|
|
40
40
|
const [audio, setAudio] = useState<{ callId: string; url: string } | null>(null);
|
|
@@ -67,13 +67,13 @@ export function CallScorecard({ callId, onDeleted, allowDelete = true, className
|
|
|
67
67
|
<div className={`flex flex-col gap-4 ${className ?? ""}`}>
|
|
68
68
|
<header className="flex flex-wrap items-start justify-between gap-3">
|
|
69
69
|
<div>
|
|
70
|
-
<h2 className="text-lg font-
|
|
70
|
+
<h2 className="text-lg font-medium">{row.prospect_name || "Practice call"}{row.prospect_company ? ` at ${row.prospect_company}` : ""}</h2>
|
|
71
71
|
<p className="text-sm text-muted-foreground">
|
|
72
72
|
{[row.user_email, row.call_mode, row.call_status, row.duration_ms ? clock(row.duration_ms) : null, row.date_of_call ? new Date(row.date_of_call).toLocaleDateString() : null].filter(Boolean).join(" - ")}
|
|
73
73
|
</p>
|
|
74
74
|
</div>
|
|
75
75
|
<div className="text-right">
|
|
76
|
-
<div data-testid="overall-score" className="text-3xl font-
|
|
76
|
+
<div data-testid="overall-score" className="text-3xl font-medium">{card?.scorePct != null ? `${Math.round(card.scorePct)}%` : "-"}</div>
|
|
77
77
|
<div className="text-xs text-muted-foreground">{card ? "overall" : "not graded yet"}</div>
|
|
78
78
|
</div>
|
|
79
79
|
</header>
|
|
@@ -94,20 +94,20 @@ export function CallScorecard({ callId, onDeleted, allowDelete = true, className
|
|
|
94
94
|
))}
|
|
95
95
|
</ul>
|
|
96
96
|
<div className="grid gap-3 sm:grid-cols-2">
|
|
97
|
-
<div><h3 className="mb-1 text-sm font-
|
|
98
|
-
<div><h3 className="mb-1 text-sm font-
|
|
97
|
+
<div><h3 className="mb-1 text-sm font-medium">Strengths</h3><ul className="list-disc pl-5 text-sm">{card.strengths.map((t, i) => <li key={i}>{t}</li>)}</ul></div>
|
|
98
|
+
<div><h3 className="mb-1 text-sm font-medium">To improve</h3><ul className="list-disc pl-5 text-sm">{card.improvements.map((t, i) => <li key={i}>{t}</li>)}</ul></div>
|
|
99
99
|
</div>
|
|
100
100
|
</>
|
|
101
101
|
)}
|
|
102
102
|
|
|
103
103
|
<div className="flex flex-col gap-2">
|
|
104
|
-
<h3 className="text-sm font-
|
|
104
|
+
<h3 className="text-sm font-medium">Recording</h3>
|
|
105
105
|
{row.audio_url ? (shownAudio ? <audio controls src={shownAudio} className="w-full" /> : <div><Button size="sm" variant="outline" loading={loadAudio.loading} onClick={() => void loadAudio.mutate(callId)}>Load recording</Button></div>) : <p className="text-sm text-muted-foreground">No recording.</p>}
|
|
106
106
|
{loadAudio.error ? <ApiError error={loadAudio.error} title="Could not load the recording" /> : null}
|
|
107
107
|
</div>
|
|
108
108
|
|
|
109
109
|
<div className="flex flex-col gap-2">
|
|
110
|
-
<h3 className="text-sm font-
|
|
110
|
+
<h3 className="text-sm font-medium">Transcript</h3>
|
|
111
111
|
{transcript.error ? <ApiError error={transcript.error} title="Could not load the transcript" onRetry={() => void transcript.refetch()} /> : null}
|
|
112
112
|
<ul className="flex max-h-96 flex-col gap-1 overflow-y-auto" data-testid="transcript">
|
|
113
113
|
{segments.map((s, i) => (
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# company-intelligence
|
|
2
|
+
|
|
3
|
+
Research **your own website** and read what it found: the company profile, competitors, brand news, products, keywords,
|
|
4
|
+
audience questions and brand assets; the wiki documents written from that research; and the six market research reports
|
|
5
|
+
(review sentiment, competitive teardown, voice of customer, GTM channels, analyst and media, buyer psychology). Billable steps
|
|
6
|
+
(a research run, a document rewrite, writing a report) are confirmed with the number of things they touch; deleting and
|
|
7
|
+
resetting are confirmed as destructive.
|
|
8
|
+
|
|
9
|
+
**What this is not.** The company intelligence API researches the workspace's own website and is locked to it. It has **no
|
|
10
|
+
lookup for other companies**, no technographics, no org chart, no firmographics for a prospect and no AI briefing endpoint (see
|
|
11
|
+
"API gaps"). The screens say so instead of inventing data.
|
|
12
|
+
|
|
13
|
+
## Screens
|
|
14
|
+
|
|
15
|
+
`CompanyIntelligenceScreen` (`components/company-intelligence-screen.tsx`) is the finished page. Copy it as your route; no props are required.
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import { CompanyIntelligenceScreen } from "@/g8/company-intelligence/components/company-intelligence-screen";
|
|
19
|
+
export default function Page() { return <CompanyIntelligenceScreen />; }
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Tabs (`?tab=`): **Overview** (start, follow and reset the research; the company profile), **Sources** (everything collected, and the sources that failed; open one with `?id=<type>` to read it and re-collect it), **Documents** (the wiki documents; `?id=` opens one to read or rewrite), **Reports** (the six reports and their workflow; `?id=` opens one). `&view=full` shows a detail as a full page.
|
|
23
|
+
|
|
24
|
+
Flows: research the website (confirmed; follows progress step by step), research again (`force`), reset the research (confirmed with the real record count), read each source (profile, competitors, news with sentiment, products, keywords, questions, trends, pages, brand assets), re-collect one source (confirmed), search and filter the wiki documents, read one as formatted text, rewrite one (confirmed), write one report or all six (confirmed with the count), retry a failed report, write the missing ones, stop a run, reset the workflow, read a report, edit its text (changed text only), approve it into the knowledge base and remove it again, read the model's recorded reasoning, write a report again, delete it. Optional props: `toolbarActions`, `renderDetailActions(record)`, `extraDetailTabs` (each `{ id, label, render(record) }`), where `record` is `{ kind: "source" | "document" | "report", id }`.
|
|
25
|
+
|
|
26
|
+
Parts you can mount alone: `ResearchRun`, `CompanyProfileCard`, `IntelligenceSources`, `SourceDetail`, `SourceView`, `WikiDocuments`, `WikiDocumentDetail`, `ResearchReports`, `ReportDetail`, and the CRM tab below.
|
|
27
|
+
|
|
28
|
+
### On a CRM company page: `CompanyIntelligenceTab`
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
<CompaniesScreen
|
|
32
|
+
extraDetailTabs={[{ id: "intelligence", label: "Intelligence", render: (c) => <CompanyIntelligenceTab company={c} /> }]}
|
|
33
|
+
/>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The stacks that include both `crm` and this block (apollo, zoominfo, clay, 6sense) already mount it. It shows the full profile when the company on screen **is** your workspace's website, the competitor entry your research holds when it is one of the competitors the research found, and otherwise says plainly that there is nothing to show. It never invents data for other companies.
|
|
37
|
+
|
|
38
|
+
## Install
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
npx @graph8/sdk add company-intelligence
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Installs `foundation` first if missing. Everything lands under `g8/company-intelligence/`. Add `intelligence`, `global-context` and `research-reports` to the proxy allowlist (the installer does this from the block's operations).
|
|
45
|
+
|
|
46
|
+
## Prerequisites (the human must do these)
|
|
47
|
+
|
|
48
|
+
| Where | What | How to verify |
|
|
49
|
+
|---|---|---|
|
|
50
|
+
| graph8 key | `knowledge:read`, `knowledge:run`, `knowledge:delete` (research, documents) and `campaigns:read`, `campaigns:write`, `campaigns:run`, `campaigns:delete` (research reports). | `g8.api.me.describeCurrentKey()` |
|
|
51
|
+
| Credits | Research runs, document rewrites and report writing spend credits. The API quotes no price and has no balance read. | The owner knows the balance. |
|
|
52
|
+
| The business | Which website is researched. The first run locks the workspace to it. | `GET /api/v1/intelligence/primary-website` shows `has_website: true`. |
|
|
53
|
+
|
|
54
|
+
## The flow, in order (IDs passed between steps)
|
|
55
|
+
|
|
56
|
+
1. **Target**: `getIntelligencePrimaryWebsite` -> `primary_website_url` (null before the first run). If null, `getIntelligenceOrgDomain` -> `company_domain` is only a **suggestion**; a person confirms it.
|
|
57
|
+
2. **Research**: `analyzeWebsite({ website_url, force? })` behind `ConfirmSpendDialog` -> **`task_id`**. A run that finished less than an hour ago is returned as is (no new work, no charge) unless `force` is true. If a primary website is set, any other website answers 400.
|
|
58
|
+
3. **Follow**: `getIntelligenceStatus(task_id)` until `status` is not `pending`/`running`; `steps` has one state per source. `getLatestIntelligenceTask` gives the last `task_id`.
|
|
59
|
+
4. **Read**: `listIntelligenceDocuments` (what was collected), `getIntelligenceData(data_type, { website_url })` (one source, 404 = not collected), `getAllIntelligenceData(website_url)` (all of them, keyed by type; `website_url` here is the host without a scheme).
|
|
60
|
+
5. **Fix one source**: `retryIntelligenceSource({ website_url, data_type })` (billable). The last good data stays if it fails.
|
|
61
|
+
6. **Wiki documents**: `getGlobalContextTreeFlat` (each has `id`, `file_type`, `content`, `status`, `version`, `credits_used`), `getGlobalContextTree` (`stats.total`, `stats.completed`), `generateGlobalContextDocument(file_type, { doc_type, website_url })` (billable, rewrites one document).
|
|
62
|
+
7. **Reports**: `getResearchWorkflowStatus({ website_url })` -> six slots `report_1..report_6` with `id`, `report_number`, `report_type`, `status`. Then `generateResearchReport({ website_url, report_number })`, `generateAllResearchReports`, `resumeResearchWorkflow`, `retryResearchReport({ website_url, report_type })` (all billable), `stopAllResearch`, `resetResearchWorkflow` (destructive). `getResearchReport(id)` has the markdown; `updateResearchReport(id, { markdown_content })`, `approveResearchReport(id)`, `unapproveResearchReport(id)`, `deleteResearchReport(id)`, `getResearchReportThinking(id)` (recorded reasoning).
|
|
63
|
+
|
|
64
|
+
## Default decisions (do not ask the human unless marked)
|
|
65
|
+
|
|
66
|
+
| Decision | Default | Ask? |
|
|
67
|
+
|---|---|---|
|
|
68
|
+
| Which website is researched | The primary website once set; the workspace settings' company domain only as a suggestion | **yes** |
|
|
69
|
+
| Run again within the hour | No: the API returns the recent run for free | no |
|
|
70
|
+
| Writing reports | Never automatic; a person confirms the number first | no |
|
|
71
|
+
| Approving a report into the knowledge base | Only when asked (campaigns and the copilot read approved reports) | **yes** |
|
|
72
|
+
| Editing a report | Send only the changed text; clearing it sends `""` | no |
|
|
73
|
+
| Missing data | A dash, never 0, never a guess | no |
|
|
74
|
+
|
|
75
|
+
## Cost, in plain numbers
|
|
76
|
+
|
|
77
|
+
The API gives **no price in advance** and no balance read, so no screen shows an invented figure. Each confirm states the quantity
|
|
78
|
+
it can compute from the data on screen, and a real "last time" number when the API reports one.
|
|
79
|
+
|
|
80
|
+
| Action | Tier | Confirm says |
|
|
81
|
+
|---|---|---|
|
|
82
|
+
| Research the website | billable | Collects the sources of the last run (their count when known); or that a run under an hour old would be returned for free; that the first website becomes locked |
|
|
83
|
+
| Re-collect one source | billable | The one source and the website |
|
|
84
|
+
| Rewrite one wiki document | billable | The document and its version; credits it used last time when the API reports them |
|
|
85
|
+
| Write one report | billable | 1 report |
|
|
86
|
+
| Write all reports | billable | The number of reports, and how many finished ones are written again |
|
|
87
|
+
| Write the missing reports | billable | The count and the titles of the unfinished reports |
|
|
88
|
+
| Retry a failed report | billable | 1 report |
|
|
89
|
+
| Save report text | billable tier (re-indexes into knowledge) | That saving re-indexes the text |
|
|
90
|
+
| Reset the research | destructive | The real number of collected sources it deletes |
|
|
91
|
+
| Reset the report workflow | destructive | The number of reports that have content |
|
|
92
|
+
| Delete a report | destructive | 1 report, and what it used last time when known |
|
|
93
|
+
| Reads, approve, unapprove, stop | none / write | (stop is confirmed too: it cancels paid work in flight) |
|
|
94
|
+
|
|
95
|
+
## Operation coverage
|
|
96
|
+
|
|
97
|
+
Used (26): `analyzeWebsite`, `getIntelligenceStatus`, `getLatestIntelligenceTask`, `getIntelligencePrimaryWebsite`, `getIntelligenceOrgDomain`, `listIntelligenceDocuments`, `getIntelligenceData`, `getAllIntelligenceData`, `retryIntelligenceSource`, `resetIntelligence`, `getGlobalContextTree`, `getGlobalContextTreeFlat`, `generateGlobalContextDocument`, `getResearchReportThinking` (the 14 `companyIntelligence` operations, all used), plus from the `research` and `gtmContext` namespaces the report operations they need: `getResearchWorkflowStatus`, `getResearchReport`, `generateResearchReport`, `generateAllResearchReports`, `resumeResearchWorkflow`, `retryResearchReport`, `stopAllResearch`, `resetResearchWorkflow`, `approveResearchReport`, `unapproveResearchReport`, `deleteResearchReport`, `updateResearchReport`.
|
|
98
|
+
|
|
99
|
+
Skipped on purpose:
|
|
100
|
+
|
|
101
|
+
| Operation | Why |
|
|
102
|
+
|---|---|
|
|
103
|
+
| `scaffoldResearchReports` | Creates six empty placeholder rows. The Reports tab already shows all six slots from the workflow status, and writing a report creates its row. |
|
|
104
|
+
| `getResearchReportByNumber` | The same report `getResearchReport` returns by id; the workflow status gives every id. |
|
|
105
|
+
| `listResearchReports` (gtmContext) | The workflow status lists the same six reports with their ids and approval state, per website. |
|
|
106
|
+
| `listIntelligenceData` (gtmContext) | The same sources as `listIntelligenceDocuments` / `getAllIntelligenceData`. |
|
|
107
|
+
| `getGlobalContextDocument`, `listGlobalContextDocuments`, `updateGlobalContextDocument`, `deleteDocument`, `deleteAllDocuments`, `regenerateGlobalContext`, `generateAllDocuments`, `resumePipeline`, `stopAllGeneration`, `scaffold*`, `reindexAllDocuments`, `resetStuckDocuments`, pipelines, highlights, analytics, feedback, usage tracking, buying-journey (gtmContext) | Wiki editing and the whole-wiki pipeline belong to the campaigns/GTM context surface, not to company intelligence. This block reads and rewrites one document at a time. |
|
|
108
|
+
|
|
109
|
+
## API gaps (what was asked for and the API does not have)
|
|
110
|
+
|
|
111
|
+
| Asked for | Reality | What the block does |
|
|
112
|
+
|---|---|---|
|
|
113
|
+
| Company profile / firmographics / technographics of **any** company | The research is of the workspace's own website and is locked to it (`analyze` answers 400 for another website). Only `company_enrichment`, `product_inventory`, `company_keywords` etc. of that one website exist. No technology-stack data at all. | Shows the own-company profile; the CRM tab says plainly that other companies have none. |
|
|
114
|
+
| News and signals for a prospect | `brand_news` is news about the workspace's own brand. Buying signals are the `intent` and `radar` blocks. | News tab content is the brand's own news. |
|
|
115
|
+
| Competitors | `competitor_discovery` lists the competitors of the workspace's website (name, domain, type, similarity, confidence, reasoning). Battle cards and tracking are the `radar` block. | Shown in Sources; the CRM tab matches a company to it by domain. |
|
|
116
|
+
| Org chart | No endpoint. Buying committees are in the `intent` block (ABM rollup). | Not offered. |
|
|
117
|
+
| AI briefings for a company | No briefing endpoint; the research reports are market-level, not per company. | Not offered. |
|
|
118
|
+
| A price before running | None, and no credit balance read. | Confirms state quantities, never a made-up cost. |
|
|
119
|
+
| Live progress stream | The thinking stream is SSE and excluded; only the recorded history is exposed. | Reasoning tab shows the recorded steps; runs are polled. |
|
|
120
|
+
| Editing collected data / Ask AI revisions | The in-app field overrides and revise endpoints are not in the developer API. | Collected data is read-only; edits made in the app are shown and flagged. |
|
|
121
|
+
| Reset everything | `DELETE /intelligence/reset-all` is deliberately not published. | Reset removes intelligence records and runs only. |
|
|
122
|
+
| Report type names | The list filter documents `industry_analyst` but the retry enum is `analyst_media`. | The block uses the retry enum. |
|
|
123
|
+
|
|
124
|
+
## Things that surprise people
|
|
125
|
+
|
|
126
|
+
- The first research run **locks** the workspace to that website and also records it as the workspace's company domain. Pick it deliberately.
|
|
127
|
+
- `analyze` is collapsed: within an hour of a finished run it returns that run (`message: "Recent analysis available"`) without new work. Pass `force` to re-run.
|
|
128
|
+
- Every payload is open-shaped. A missing field is unknown, not zero.
|
|
129
|
+
- Web content (article titles, snippets, scraped pages, report markdown) is untrusted. This block draws it as text; links open only when they are http(s).
|
|
130
|
+
- A report's `credits_used` is `0` until it ran; the UI shows a dash, not 0.
|
|
131
|
+
- `getIntelligenceData` answers 404 for a source that was never collected; that is "not collected", not an outage.
|
|
132
|
+
- Reports need the website: `getResearchWorkflowStatus` requires `website_url`.
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../block.schema.json",
|
|
3
|
+
"id": "company-intelligence",
|
|
4
|
+
"title": "Company intelligence",
|
|
5
|
+
"summary": "Research your own website, then read what it found (profile, competitors, news, keywords), the wiki documents written from it and the six market research reports. Billable steps are confirmed.",
|
|
6
|
+
"features": [
|
|
7
|
+
"website research run with step-by-step progress; billable, confirmed, locked to the workspace's own website",
|
|
8
|
+
"company profile, competitors, brand news, products, keywords, audience questions and brand assets, each readable and re-collectable",
|
|
9
|
+
"wiki documents written from the research, read as safe formatted text and rewritten one at a time",
|
|
10
|
+
"six research reports: write one or all, retry, resume, stop, reset; read, edit, approve into the knowledge base, see the model's reasoning, delete",
|
|
11
|
+
"optional tab for a CRM company page (CompanyIntelligenceTab)",
|
|
12
|
+
"markdown and web content from the API is always drawn as text, never as HTML"
|
|
13
|
+
],
|
|
14
|
+
"dependsOn": [
|
|
15
|
+
"foundation"
|
|
16
|
+
],
|
|
17
|
+
"operations": [
|
|
18
|
+
"analyze_website_intelligence_analyze_post",
|
|
19
|
+
"approve_research_report_research_reports__report_id__approve_post",
|
|
20
|
+
"delete_research_report_research_reports__report_id__delete",
|
|
21
|
+
"generate_all_research_reports_research_reports_generate_all_post",
|
|
22
|
+
"generate_global_context_document_global_context_generate__doc_type__post",
|
|
23
|
+
"generate_research_report_research_reports_generate_post",
|
|
24
|
+
"get_all_intelligence_data_intelligence_all__website_url__get",
|
|
25
|
+
"get_global_context_tree_flat_global_context_tree_flat_get",
|
|
26
|
+
"get_global_context_tree_global_context_tree_get",
|
|
27
|
+
"get_intelligence_data_intelligence_data__data_type__get",
|
|
28
|
+
"get_intelligence_org_domain_intelligence_org_domain_get",
|
|
29
|
+
"get_intelligence_primary_website_intelligence_primary_website_get",
|
|
30
|
+
"get_intelligence_status_intelligence_status__task_id__get",
|
|
31
|
+
"get_latest_intelligence_task_intelligence_latest_task_get",
|
|
32
|
+
"get_research_report_research_reports__report_id__get",
|
|
33
|
+
"get_research_report_thinking_research_reports__report_id__thinking_get",
|
|
34
|
+
"get_research_workflow_status_research_reports_workflow_get",
|
|
35
|
+
"list_intelligence_documents_intelligence_documents_get",
|
|
36
|
+
"reset_intelligence_intelligence_delete",
|
|
37
|
+
"reset_research_workflow_research_reports_workflow_reset_post",
|
|
38
|
+
"resume_research_workflow_research_reports_workflow_resume_post",
|
|
39
|
+
"retry_intelligence_source_intelligence_retry_post",
|
|
40
|
+
"retry_research_report_research_reports_retry_post",
|
|
41
|
+
"stop_all_research_research_reports_stop_all_post",
|
|
42
|
+
"unapprove_research_report_research_reports__report_id__unapprove_post",
|
|
43
|
+
"update_research_report_research_reports__report_id__patch"
|
|
44
|
+
],
|
|
45
|
+
"components": [
|
|
46
|
+
{
|
|
47
|
+
"name": "ResearchRun",
|
|
48
|
+
"file": "components/research-run.tsx",
|
|
49
|
+
"purpose": "Start the website research (billable, confirmed), follow it step by step, and reset it (destructive, confirmed with the real record count).",
|
|
50
|
+
"operations": [
|
|
51
|
+
"analyze_website_intelligence_analyze_post",
|
|
52
|
+
"get_intelligence_org_domain_intelligence_org_domain_get",
|
|
53
|
+
"get_intelligence_primary_website_intelligence_primary_website_get",
|
|
54
|
+
"get_intelligence_status_intelligence_status__task_id__get",
|
|
55
|
+
"get_latest_intelligence_task_intelligence_latest_task_get",
|
|
56
|
+
"list_intelligence_documents_intelligence_documents_get",
|
|
57
|
+
"reset_intelligence_intelligence_delete"
|
|
58
|
+
],
|
|
59
|
+
"tiers": [
|
|
60
|
+
"read",
|
|
61
|
+
"billable",
|
|
62
|
+
"destructive"
|
|
63
|
+
]
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"name": "CompanyProfileCard",
|
|
67
|
+
"file": "components/company-profile.tsx",
|
|
68
|
+
"purpose": "The company profile the research collected (industry, size, funding, links) with counts of what else was found. Mount alone on any page.",
|
|
69
|
+
"operations": [
|
|
70
|
+
"get_all_intelligence_data_intelligence_all__website_url__get",
|
|
71
|
+
"get_intelligence_primary_website_intelligence_primary_website_get"
|
|
72
|
+
],
|
|
73
|
+
"tiers": [
|
|
74
|
+
"read"
|
|
75
|
+
]
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"name": "IntelligenceSources",
|
|
79
|
+
"file": "components/intelligence-sources.tsx",
|
|
80
|
+
"purpose": "List of the collected data sources plus the ones of the last run that failed or have not finished.",
|
|
81
|
+
"operations": [
|
|
82
|
+
"get_intelligence_status_intelligence_status__task_id__get",
|
|
83
|
+
"get_latest_intelligence_task_intelligence_latest_task_get",
|
|
84
|
+
"list_intelligence_documents_intelligence_documents_get"
|
|
85
|
+
],
|
|
86
|
+
"tiers": [
|
|
87
|
+
"read"
|
|
88
|
+
]
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"name": "SourceDetail",
|
|
92
|
+
"file": "components/source-detail.tsx",
|
|
93
|
+
"purpose": "Complete screen for one source: what it collected, when, edits, and re-collect it (billable, confirmed).",
|
|
94
|
+
"operations": [
|
|
95
|
+
"get_intelligence_data_intelligence_data__data_type__get",
|
|
96
|
+
"get_intelligence_primary_website_intelligence_primary_website_get",
|
|
97
|
+
"retry_intelligence_source_intelligence_retry_post"
|
|
98
|
+
],
|
|
99
|
+
"tiers": [
|
|
100
|
+
"read",
|
|
101
|
+
"billable"
|
|
102
|
+
]
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"name": "SourceView",
|
|
106
|
+
"file": "components/source-view.tsx",
|
|
107
|
+
"purpose": "Read-only renderer for one source's data: profile, competitors, news, products, keywords, questions, trends, pages, brand assets; unknown shapes fall back to a readable tree.",
|
|
108
|
+
"operations": [],
|
|
109
|
+
"tiers": []
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"name": "WikiDocuments",
|
|
113
|
+
"file": "components/wiki-documents.tsx",
|
|
114
|
+
"purpose": "The wiki documents written from the research, with search and a folder filter.",
|
|
115
|
+
"operations": [
|
|
116
|
+
"get_global_context_tree_flat_global_context_tree_flat_get"
|
|
117
|
+
],
|
|
118
|
+
"tiers": [
|
|
119
|
+
"read"
|
|
120
|
+
]
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"name": "WikiDocumentDetail",
|
|
124
|
+
"file": "components/wiki-document-detail.tsx",
|
|
125
|
+
"purpose": "Complete screen for one wiki document: safe formatted content, state, version, and rewrite it from the research (billable, confirmed).",
|
|
126
|
+
"operations": [
|
|
127
|
+
"generate_global_context_document_global_context_generate__doc_type__post",
|
|
128
|
+
"get_global_context_tree_flat_global_context_tree_flat_get",
|
|
129
|
+
"get_intelligence_primary_website_intelligence_primary_website_get"
|
|
130
|
+
],
|
|
131
|
+
"tiers": [
|
|
132
|
+
"read",
|
|
133
|
+
"billable"
|
|
134
|
+
]
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
"name": "ResearchReports",
|
|
138
|
+
"file": "components/research-reports.tsx",
|
|
139
|
+
"purpose": "The six research reports and their workflow: write one or all, retry, resume, stop, reset; every cost confirmed with the number of reports.",
|
|
140
|
+
"operations": [
|
|
141
|
+
"generate_all_research_reports_research_reports_generate_all_post",
|
|
142
|
+
"generate_research_report_research_reports_generate_post",
|
|
143
|
+
"get_intelligence_primary_website_intelligence_primary_website_get",
|
|
144
|
+
"get_research_workflow_status_research_reports_workflow_get",
|
|
145
|
+
"reset_research_workflow_research_reports_workflow_reset_post",
|
|
146
|
+
"resume_research_workflow_research_reports_workflow_resume_post",
|
|
147
|
+
"retry_research_report_research_reports_retry_post",
|
|
148
|
+
"stop_all_research_research_reports_stop_all_post"
|
|
149
|
+
],
|
|
150
|
+
"tiers": [
|
|
151
|
+
"read",
|
|
152
|
+
"write",
|
|
153
|
+
"billable",
|
|
154
|
+
"destructive"
|
|
155
|
+
]
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
"name": "ReportDetail",
|
|
159
|
+
"file": "components/report-detail.tsx",
|
|
160
|
+
"purpose": "Complete screen for one research report: safe formatted text, edit (changed text only), approve into the knowledge base, recorded reasoning, write again, delete.",
|
|
161
|
+
"operations": [
|
|
162
|
+
"approve_research_report_research_reports__report_id__approve_post",
|
|
163
|
+
"delete_research_report_research_reports__report_id__delete",
|
|
164
|
+
"generate_research_report_research_reports_generate_post",
|
|
165
|
+
"get_intelligence_primary_website_intelligence_primary_website_get",
|
|
166
|
+
"get_research_report_research_reports__report_id__get",
|
|
167
|
+
"get_research_report_thinking_research_reports__report_id__thinking_get",
|
|
168
|
+
"unapprove_research_report_research_reports__report_id__unapprove_post",
|
|
169
|
+
"update_research_report_research_reports__report_id__patch"
|
|
170
|
+
],
|
|
171
|
+
"tiers": [
|
|
172
|
+
"read",
|
|
173
|
+
"write",
|
|
174
|
+
"billable",
|
|
175
|
+
"destructive"
|
|
176
|
+
]
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
"name": "CompanyIntelligenceTab",
|
|
180
|
+
"file": "components/company-intelligence-tab.tsx",
|
|
181
|
+
"purpose": "Optional tab for a CRM company detail page (mount through extraDetailTabs): the profile when the company is your own website, the competitor entry when it is a competitor your research found, otherwise an honest empty state.",
|
|
182
|
+
"operations": [
|
|
183
|
+
"get_all_intelligence_data_intelligence_all__website_url__get",
|
|
184
|
+
"get_intelligence_data_intelligence_data__data_type__get",
|
|
185
|
+
"get_intelligence_primary_website_intelligence_primary_website_get"
|
|
186
|
+
],
|
|
187
|
+
"tiers": [
|
|
188
|
+
"read"
|
|
189
|
+
]
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
"name": "CompanyIntelligenceScreen",
|
|
193
|
+
"file": "components/company-intelligence-screen.tsx",
|
|
194
|
+
"purpose": "Finished company-intelligence page: Overview (research run + profile), Sources, Documents and Reports tabs, each with a detail panel and deep links.",
|
|
195
|
+
"operations": [
|
|
196
|
+
"get_global_context_tree_global_context_tree_get",
|
|
197
|
+
"get_intelligence_primary_website_intelligence_primary_website_get",
|
|
198
|
+
"get_latest_intelligence_task_intelligence_latest_task_get",
|
|
199
|
+
"get_research_workflow_status_research_reports_workflow_get",
|
|
200
|
+
"list_intelligence_documents_intelligence_documents_get"
|
|
201
|
+
],
|
|
202
|
+
"tiers": [
|
|
203
|
+
"read"
|
|
204
|
+
]
|
|
205
|
+
}
|
|
206
|
+
],
|
|
207
|
+
"hooks": [
|
|
208
|
+
{
|
|
209
|
+
"name": "useResearchTarget",
|
|
210
|
+
"file": "hooks/use-intelligence.ts",
|
|
211
|
+
"purpose": "Cached reads shared by the components: useResearchTarget (primary website + a suggestion), useLatestRun, useRunStatus, useSourceDocuments, useSourceEntry, useAllIntelligence, useWikiDocuments, useWikiStats, useWorkflow, and refreshIntelligence() to refresh them all after a write.",
|
|
212
|
+
"operations": [
|
|
213
|
+
"get_all_intelligence_data_intelligence_all__website_url__get",
|
|
214
|
+
"get_global_context_tree_flat_global_context_tree_flat_get",
|
|
215
|
+
"get_global_context_tree_global_context_tree_get",
|
|
216
|
+
"get_intelligence_data_intelligence_data__data_type__get",
|
|
217
|
+
"get_intelligence_org_domain_intelligence_org_domain_get",
|
|
218
|
+
"get_intelligence_primary_website_intelligence_primary_website_get",
|
|
219
|
+
"get_intelligence_status_intelligence_status__task_id__get",
|
|
220
|
+
"get_latest_intelligence_task_intelligence_latest_task_get",
|
|
221
|
+
"get_research_workflow_status_research_reports_workflow_get",
|
|
222
|
+
"list_intelligence_documents_intelligence_documents_get"
|
|
223
|
+
]
|
|
224
|
+
}
|
|
225
|
+
],
|
|
226
|
+
"lib": [
|
|
227
|
+
{
|
|
228
|
+
"file": "lib/intelligence-types.ts",
|
|
229
|
+
"purpose": "Open-payload types, defensive readers (text, num, rowsOf), canonicalDomain, safeHttpUrl, run/step helpers, the six report types, workflow slot helpers, and the changed-text-only report edit."
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
"file": "lib/safe-markdown.tsx",
|
|
233
|
+
"purpose": "SafeMarkdown: renders API markdown as React text nodes (headings, lists, tables, code, links to http(s) only). Never produces HTML; no dangerouslySetInnerHTML."
|
|
234
|
+
}
|
|
235
|
+
],
|
|
236
|
+
"recipes": [
|
|
237
|
+
{
|
|
238
|
+
"file": "recipes/research-your-website.ts",
|
|
239
|
+
"title": "Research your own website and read the company profile",
|
|
240
|
+
"when": "Setting up company intelligence: primary website, billable run, poll, read the profile."
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
"file": "recipes/read-competitors-and-news.ts",
|
|
244
|
+
"title": "Read the competitors and the news the research found",
|
|
245
|
+
"when": "Feeding a briefing or digest from the collected competitors and brand news."
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
"file": "recipes/write-the-research-reports.ts",
|
|
249
|
+
"title": "Write the six research reports, follow them and approve one",
|
|
250
|
+
"when": "Building market research: count the missing reports, get a yes, write, poll, read, approve."
|
|
251
|
+
}
|
|
252
|
+
],
|
|
253
|
+
"prerequisites": [
|
|
254
|
+
{
|
|
255
|
+
"id": "intelligence-scopes",
|
|
256
|
+
"description": "The graph8 key needs knowledge:read, knowledge:run and knowledge:delete (research and documents) and campaigns:read, campaigns:write, campaigns:run, campaigns:delete (research reports).",
|
|
257
|
+
"where": "api",
|
|
258
|
+
"verify": "g8.api.me.describeCurrentKey() lists those scopes."
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
"id": "credits",
|
|
262
|
+
"description": "Research runs, document rewrites and report writing use credits. The API quotes no price in advance, so a person confirms each one.",
|
|
263
|
+
"where": "api",
|
|
264
|
+
"verify": "The workspace owner knows the plan's credit balance (the API has no balance read)."
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
"id": "own-website",
|
|
268
|
+
"description": "The research is about the workspace's own website and is locked to the first one researched. A person decides which website that is.",
|
|
269
|
+
"where": "app",
|
|
270
|
+
"verify": "GET /api/v1/intelligence/primary-website returns has_website true after the first run."
|
|
271
|
+
}
|
|
272
|
+
],
|
|
273
|
+
"scopes": [
|
|
274
|
+
"campaigns:delete",
|
|
275
|
+
"campaigns:read",
|
|
276
|
+
"campaigns:run",
|
|
277
|
+
"campaigns:write",
|
|
278
|
+
"knowledge:delete",
|
|
279
|
+
"knowledge:read",
|
|
280
|
+
"knowledge:run"
|
|
281
|
+
],
|
|
282
|
+
"defaults": [
|
|
283
|
+
{
|
|
284
|
+
"decision": "Which website is researched",
|
|
285
|
+
"default": "The workspace's primary website once set; before that the company domain from the workspace settings is only suggested, a person confirms it",
|
|
286
|
+
"askHuman": true
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
"decision": "Run again when a run finished less than an hour ago",
|
|
290
|
+
"default": "No: the API returns that run and does no new work",
|
|
291
|
+
"askHuman": false
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
"decision": "Writing a research report",
|
|
295
|
+
"default": "Never automatic: a person confirms the number of reports first",
|
|
296
|
+
"askHuman": false
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
"decision": "Approving a report into the knowledge base",
|
|
300
|
+
"default": "Only when a person asks; approved reports are read by campaigns and the copilot",
|
|
301
|
+
"askHuman": true
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
"decision": "Editing a report",
|
|
305
|
+
"default": "Send only the changed text; a cleared text is sent as an empty string",
|
|
306
|
+
"askHuman": false
|
|
307
|
+
},
|
|
308
|
+
{
|
|
309
|
+
"decision": "Missing data",
|
|
310
|
+
"default": "Shown as unknown (a dash), never as zero and never guessed",
|
|
311
|
+
"askHuman": false
|
|
312
|
+
}
|
|
313
|
+
],
|
|
314
|
+
"peerDependencies": {
|
|
315
|
+
"react": ">=18",
|
|
316
|
+
"lucide-react": ">=0.400"
|
|
317
|
+
}
|
|
318
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* CompanyIntelligenceScreen: the finished company-intelligence page. Four tabs (`?tab=`):
|
|
5
|
+
* Overview start, follow and reset the website research (ResearchRun) and read the company profile it collected.
|
|
6
|
+
* Sources everything the research collected, and the sources that failed; open one (`?id=<type>`) to read it and re-collect it.
|
|
7
|
+
* Documents the wiki documents written from the research; open one (`?id=`) to read it or write it again.
|
|
8
|
+
* Reports the six research reports and their workflow: write, retry, resume, stop, reset; open one (`?id=`) to read,
|
|
9
|
+
* edit, approve into the knowledge base, see the reasoning, write again or delete.
|
|
10
|
+
* Every detail also opens as a full page with `?view=full`. Every write refreshes the shared read cache, so the stat strip and
|
|
11
|
+
* the lists update without a reload.
|
|
12
|
+
*
|
|
13
|
+
* Reality of the API: this is the research of YOUR OWN workspace website (locked to one website); it has no lookup for other
|
|
14
|
+
* companies and no technographics, org chart or briefing endpoints. The screen says so instead of inventing data. To show a
|
|
15
|
+
* company's intelligence on a CRM company page, mount `CompanyIntelligenceTab` in the CRM block's `extraDetailTabs`.
|
|
16
|
+
*
|
|
17
|
+
* SDK operations: none of its own; the stat strip reads listIntelligenceDocuments, getGlobalContextTree,
|
|
18
|
+
* getResearchWorkflowStatus and getLatestIntelligenceTask (all free reads). Everything billable or destructive is inside the parts
|
|
19
|
+
* it composes (ResearchRun, SourceDetail, WikiDocumentDetail, ResearchReports, ReportDetail), each behind ConfirmSpendDialog.
|
|
20
|
+
* Prerequisites: `intelligence`, `global-context` and `research-reports` in the proxy allowlist; credits for research.
|
|
21
|
+
*/
|
|
22
|
+
import type { ReactNode } from "react";
|
|
23
|
+
import { Telescope } from "lucide-react";
|
|
24
|
+
import { Button } from "@graph8/sdk/ui";
|
|
25
|
+
import { useUrlState } from "@/g8/hooks/use-url-state";
|
|
26
|
+
import { ScreenLayout } from "@/g8/components/screen/screen-layout";
|
|
27
|
+
import type { StatItem } from "@/g8/components/screen/stat-strip";
|
|
28
|
+
import { SplitView } from "@/g8/components/screen/split-view";
|
|
29
|
+
import { EmptyValue } from "@/g8/components/screen/key-value-list";
|
|
30
|
+
import { plural } from "@/g8/lib/plural";
|
|
31
|
+
import { useLatestRun, useResearchTarget, useSourceDocuments, useWikiStats, useWorkflow } from "../hooks/use-intelligence";
|
|
32
|
+
import { humanize, isReportDone, slotsOf, whenDate } from "../lib/intelligence-types";
|
|
33
|
+
import { CompanyProfileCard } from "./company-profile";
|
|
34
|
+
import { IntelligenceSources } from "./intelligence-sources";
|
|
35
|
+
import { ReportDetail } from "./report-detail";
|
|
36
|
+
import { ResearchReports } from "./research-reports";
|
|
37
|
+
import { ResearchRun } from "./research-run";
|
|
38
|
+
import { SourceDetail } from "./source-detail";
|
|
39
|
+
import { WikiDocumentDetail } from "./wiki-document-detail";
|
|
40
|
+
import { WikiDocuments } from "./wiki-documents";
|
|
41
|
+
|
|
42
|
+
/** The record open in the detail panel, passed to the slot props. */
|
|
43
|
+
export type IntelligenceRecord = { kind: "source" | "document" | "report"; id: string };
|
|
44
|
+
|
|
45
|
+
export interface CompanyIntelligenceScreenProps {
|
|
46
|
+
toolbarActions?: ReactNode;
|
|
47
|
+
/** Buttons added to the open record's header. */
|
|
48
|
+
renderDetailActions?: (record: IntelligenceRecord) => ReactNode;
|
|
49
|
+
/** Tabs added after the built-in ones on the open record. */
|
|
50
|
+
extraDetailTabs?: { id: string; label: string; render: (record: IntelligenceRecord) => ReactNode }[];
|
|
51
|
+
className?: string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
type Tab = "overview" | "sources" | "documents" | "reports";
|
|
55
|
+
const TABS = ["overview", "sources", "documents", "reports"] as const;
|
|
56
|
+
|
|
57
|
+
export function CompanyIntelligenceScreen(props: CompanyIntelligenceScreenProps) {
|
|
58
|
+
const [tabValue, setTab] = useUrlState("tab", "overview");
|
|
59
|
+
const tab: Tab = (TABS as readonly string[]).includes(tabValue) ? (tabValue as Tab) : "overview";
|
|
60
|
+
const [id, setId] = useUrlState("id", "");
|
|
61
|
+
const [view, setView] = useUrlState("view", "");
|
|
62
|
+
const expanded = view === "full" && Boolean(id);
|
|
63
|
+
const target = useResearchTarget();
|
|
64
|
+
const docs = useSourceDocuments();
|
|
65
|
+
const wiki = useWikiStats();
|
|
66
|
+
const flow = useWorkflow(target.primary);
|
|
67
|
+
const latest = useLatestRun();
|
|
68
|
+
|
|
69
|
+
const close = () => { setId(""); setView(""); };
|
|
70
|
+
const panel = { onClose: close, onExpand: expanded ? undefined : () => setView("full"), onCollapse: expanded ? () => setView("") : undefined };
|
|
71
|
+
const slots = (record: IntelligenceRecord) => ({
|
|
72
|
+
extraActions: props.renderDetailActions?.(record),
|
|
73
|
+
extraTabs: (props.extraDetailTabs ?? []).map((t) => ({ id: t.id, label: t.label, content: t.render(record) })),
|
|
74
|
+
});
|
|
75
|
+
const split = (list: ReactNode, detail: ReactNode) => (
|
|
76
|
+
<SplitView detailOpen={Boolean(id)} onCloseDetail={close} expanded={expanded} onExpandedChange={(next) => setView(next ? "full" : "")} detailWidth="lg" list={list} detail={id ? detail : null} />
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
const reportSlots = slotsOf(flow.workflow ?? undefined);
|
|
80
|
+
const stats: StatItem[] = [
|
|
81
|
+
{ label: "Sources collected", value: docs.docs ? docs.docs.length.toLocaleString() : <EmptyValue /> },
|
|
82
|
+
{ label: "Wiki documents", value: wiki.stats ? `${wiki.stats.completed.toLocaleString()} of ${wiki.stats.total.toLocaleString()}` : <EmptyValue />, hint: wiki.stats ? "finished" : undefined },
|
|
83
|
+
{ label: "Research reports", value: flow.workflow ? `${reportSlots.filter((s) => isReportDone(s.status)).length} of ${reportSlots.length || 6}` : <EmptyValue />, hint: flow.workflow ? "finished" : undefined },
|
|
84
|
+
{ label: "Last research", value: latest.run?.status ? humanize(latest.run.status) : <EmptyValue />, hint: latest.run?.completed_at ? whenDate(latest.run.completed_at) ?? undefined : latest.run ? undefined : "none yet", tone: latest.run?.status === "failed" ? "negative" : "neutral" },
|
|
85
|
+
];
|
|
86
|
+
|
|
87
|
+
return (
|
|
88
|
+
<ScreenLayout
|
|
89
|
+
title="Company intelligence"
|
|
90
|
+
description="What the research of your website found, and the documents and reports written from it."
|
|
91
|
+
icon={<Telescope className="size-5" />}
|
|
92
|
+
actions={<>{props.toolbarActions}{tab === "overview" ? null : <Button onClick={() => { setTab("overview"); close(); }}>Research website</Button>}</>}
|
|
93
|
+
tabs={[{ id: "overview", label: "Overview" }, { id: "sources", label: "Sources" }, { id: "documents", label: "Documents" }, { id: "reports", label: "Reports" }]}
|
|
94
|
+
activeTab={tab}
|
|
95
|
+
onTabChange={(next) => { setTab(next); close(); }}
|
|
96
|
+
stats={stats}
|
|
97
|
+
className={props.className}
|
|
98
|
+
>
|
|
99
|
+
{tab === "overview" ? (
|
|
100
|
+
<div className="space-y-4">
|
|
101
|
+
<ResearchRun />
|
|
102
|
+
<CompanyProfileCard onOpenSource={(type) => { setTab("sources"); setId(type); }} />
|
|
103
|
+
<p className="text-xs text-muted-foreground">{plural(docs.docs?.length ?? 0, "source")} collected. This is the research of your own website: there is no lookup for other companies.</p>
|
|
104
|
+
</div>
|
|
105
|
+
) : tab === "sources" ? (
|
|
106
|
+
split(<IntelligenceSources idParam="id" selectedType={id} onSelect={(s) => setId(s.dataType)} />, <SourceDetail key={id} dataType={id} {...panel} {...slots({ kind: "source", id })} />)
|
|
107
|
+
) : tab === "documents" ? (
|
|
108
|
+
split(<WikiDocuments idParam="id" selectedId={id} onSelect={(d) => setId(d.id)} />, <WikiDocumentDetail key={id} docId={id} {...panel} {...slots({ kind: "document", id })} />)
|
|
109
|
+
) : (
|
|
110
|
+
split(<ResearchReports idParam="id" selectedId={id} onSelect={(s) => s.id && setId(s.id)} />, <ReportDetail key={id} reportId={id} {...panel} {...slots({ kind: "report", id })} />)
|
|
111
|
+
)}
|
|
112
|
+
</ScreenLayout>
|
|
113
|
+
);
|
|
114
|
+
}
|