gloomberb 0.15.7 → 0.16.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 +11 -2
- package/package.json +1 -1
- package/src/api-client/app-attention.ts +147 -0
- package/src/api-client/attention.ts +26 -0
- package/src/api-client/awards.ts +215 -0
- package/src/api-client/catalysts.ts +160 -0
- package/src/api-client/chat.ts +137 -14
- package/src/api-client/company-kpis.ts +153 -0
- package/src/api-client/cpi.ts +52 -0
- package/src/api-client/credit-documents.ts +107 -0
- package/src/api-client/data.ts +192 -3
- package/src/api-client/distress.ts +164 -0
- package/src/api-client/doe.ts +75 -0
- package/src/api-client/equity-screener.ts +11 -0
- package/src/api-client/exposure.ts +202 -0
- package/src/api-client/gpu.ts +93 -0
- package/src/api-client/hiring.ts +110 -0
- package/src/api-client/index.ts +78 -3
- package/src/api-client/normalizers.ts +31 -1
- package/src/api-client/paths.ts +3 -0
- package/src/api-client/perps.ts +127 -0
- package/src/api-client/power.ts +148 -0
- package/src/api-client/request.ts +58 -1
- package/src/api-client/research-activity.ts +172 -13
- package/src/api-client/socket.ts +75 -27
- package/src/api-client/supply-chain-graph.ts +40 -0
- package/src/api-client/supply-chain.ts +98 -0
- package/src/api-client/telemetry.ts +29 -0
- package/src/api-client/themes.ts +28 -0
- package/src/api-client/types.ts +33 -1
- package/src/api-client/wall-experiments.ts +100 -0
- package/src/api-client/wall-summary.ts +49 -0
- package/src/api-client/web-experiments.ts +136 -0
- package/src/app/pane-runtime/plugin-bindings.ts +5 -0
- package/src/app/pane-runtime/ticker-open-runtime.ts +8 -2
- package/src/app/runtime/update.ts +13 -1
- package/src/cli/commands/system.ts +2 -0
- package/src/cli/desktop-pane-shot.ts +3 -4
- package/src/cli/pane-functions/data.ts +78 -0
- package/src/cli/pane-functions/financial-ratio-shot.ts +160 -0
- package/src/cli/pane-functions/function-help.ts +220 -8
- package/src/cli/pane-functions/headless.ts +4 -0
- package/src/cli/pane-functions/screenshot-evidence.ts +21 -0
- package/src/cli/pane-functions/screenshot.ts +49 -5
- package/src/components/chart/composite/composite-chart.tsx +15 -2
- package/src/components/chart/composite/format.ts +24 -11
- package/src/components/chart/composite/rasterizer.ts +67 -16
- package/src/components/chart/composite/scene.ts +53 -2
- package/src/components/chart/composite/session-shading.ts +3 -2
- package/src/components/chart/composite/text-renderer.ts +52 -1
- package/src/components/chart/composite/time-axis.ts +100 -30
- package/src/components/chart/composite/tools.ts +2 -1
- package/src/components/chart/composite/types.ts +4 -0
- package/src/components/chart-table/index.ts +1 -0
- package/src/components/chart-table/layout.ts +15 -0
- package/src/components/command-bar/action-runtime.ts +1 -0
- package/src/components/command-bar/commands/direct/index.ts +32 -0
- package/src/components/command-bar/commands/registry.ts +7 -0
- package/src/components/command-bar/pane-templates/items.ts +11 -0
- package/src/components/command-bar/pane-templates/workflow.ts +19 -4
- package/src/components/command-bar/routes/root/command-items.ts +6 -0
- package/src/components/command-bar/routes/root/provider-search.ts +2 -0
- package/src/components/command-bar/routes/root/results.ts +64 -0
- package/src/components/command-bar/routes/root/runtime.ts +8 -0
- package/src/components/command-bar/routes/ticker-search/results.ts +89 -24
- package/src/components/command-bar/routes/ticker-search/route.ts +2 -0
- package/src/components/command-bar/surface/index.tsx +15 -0
- package/src/components/command-bar/view-model.ts +3 -0
- package/src/components/command-bar/workflow/collection-actions.ts +9 -7
- package/src/components/command-bar/workflow/ops.ts +19 -0
- package/src/components/command-bar/workflow/tickers.ts +5 -0
- package/src/components/company-logo.tsx +15 -2
- package/src/components/data-table/table-pane.ts +2 -1
- package/src/components/index.ts +1 -0
- package/src/components/layout/detached-pane-shell.tsx +12 -1
- package/src/components/layout/missing-pane.tsx +87 -23
- package/src/components/layout/pane/footer/index.tsx +64 -18
- package/src/components/layout/pane/footer/model.ts +85 -0
- package/src/components/layout/pane/sidebar.tsx +19 -1
- package/src/components/layout/shell/index.tsx +38 -28
- package/src/components/layout/shell/pane/management-shortcuts.ts +13 -1
- package/src/components/layout/status-bar.tsx +93 -28
- package/src/components/layout/status-widget-space.ts +72 -0
- package/src/components/onboarding/first-run-workspace.ts +8 -2
- package/src/components/onboarding/onboarding-wizard.tsx +35 -16
- package/src/components/onboarding/portfolio-step/positions-panel.tsx +14 -5
- package/src/components/onboarding/wizard-model.ts +13 -5
- package/src/components/onboarding/wizard-positions.ts +56 -7
- package/src/components/price-performance.tsx +31 -34
- package/src/components/ui/data-table/index.tsx +11 -8
- package/src/components/ui/display.tsx +15 -6
- package/src/components/ui/fields.tsx +5 -0
- package/src/components/ui/figure.tsx +94 -0
- package/src/components/ui/header-case.ts +25 -3
- package/src/components/ui/icon.tsx +3 -1
- package/src/components/ui/message-composer.tsx +8 -1
- package/src/components/ui/query-bar.tsx +8 -1
- package/src/components/ui/ratio-bar.tsx +84 -0
- package/src/components/ui/toggle.tsx +3 -1
- package/src/components/use-scrollbox-layout.ts +17 -0
- package/src/core/state/app/layout.ts +35 -1
- package/src/core/state/app/state.ts +15 -0
- package/src/core/state/app/types.ts +1 -0
- package/src/data/config/store/normalize.ts +24 -0
- package/src/i18n/es.ts +2 -0
- package/src/i18n/ja.ts +2 -0
- package/src/i18n/ko.ts +2 -0
- package/src/i18n/zh-cn.ts +2 -0
- package/src/i18n/zh-tw.ts +2 -0
- package/src/layout-marketplace/pane-imagery.ts +1 -0
- package/src/market-data/coordinator/entries.ts +13 -0
- package/src/market-data/coordinator/financials.ts +33 -8
- package/src/market-data/market/freshness.ts +16 -5
- package/src/market-data/market/trading-sessions.ts +65 -1
- package/src/market-data/published-cn-sessions.ts +25 -0
- package/src/market-data/published-nse-sessions.ts +20 -0
- package/src/news/aggregator.ts +4 -0
- package/src/plugins/builtin/account-management/model.ts +6 -1
- package/src/plugins/builtin/account-management/pane.tsx +36 -25
- package/src/plugins/builtin/alerts/catalysts.ts +77 -0
- package/src/plugins/builtin/alerts/events-pane.tsx +3 -0
- package/src/plugins/builtin/alerts/events.ts +10 -4
- package/src/plugins/builtin/alerts/history-pane.tsx +1 -1
- package/src/plugins/builtin/alerts/history.ts +1 -0
- package/src/plugins/builtin/alerts/index.tsx +6 -0
- package/src/plugins/builtin/alerts/research-builder.ts +10 -3
- package/src/plugins/builtin/alerts/research-rules.ts +15 -1
- package/src/plugins/builtin/analytics/risk-client.ts +15 -3
- package/src/plugins/builtin/analytics/risk-headless.ts +123 -18
- package/src/plugins/builtin/attention/client.ts +80 -0
- package/src/plugins/builtin/attention/evidence.ts +30 -0
- package/src/plugins/builtin/attention/headless.ts +33 -0
- package/src/plugins/builtin/attention/index.tsx +18 -0
- package/src/plugins/builtin/attention/model.ts +59 -0
- package/src/plugins/builtin/attention/pane.tsx +211 -0
- package/src/plugins/builtin/attention/trending.tsx +59 -0
- package/src/plugins/builtin/awards/alerts.ts +32 -0
- package/src/plugins/builtin/awards/client.ts +82 -0
- package/src/plugins/builtin/awards/detail.tsx +107 -0
- package/src/plugins/builtin/awards/evidence.ts +36 -0
- package/src/plugins/builtin/awards/headless.ts +55 -0
- package/src/plugins/builtin/awards/index.tsx +20 -0
- package/src/plugins/builtin/awards/model.ts +42 -0
- package/src/plugins/builtin/awards/pane.tsx +263 -0
- package/src/plugins/builtin/catalysts/client.ts +28 -0
- package/src/plugins/builtin/catalysts/detail.tsx +88 -0
- package/src/plugins/builtin/catalysts/evidence.ts +47 -0
- package/src/plugins/builtin/catalysts/headless.ts +42 -0
- package/src/plugins/builtin/catalysts/history.ts +26 -0
- package/src/plugins/builtin/catalysts/index.tsx +29 -0
- package/src/plugins/builtin/catalysts/model.ts +135 -0
- package/src/plugins/builtin/catalysts/pane.tsx +159 -0
- package/src/plugins/builtin/chart-composer/cli-options.ts +4 -0
- package/src/plugins/builtin/chart-composer/headless-schema.ts +6 -0
- package/src/plugins/builtin/chart-composer/index.tsx +8 -1
- package/src/plugins/builtin/chart-composer/pane.tsx +28 -1
- package/src/plugins/builtin/chat/attachments/desktop.tsx +610 -0
- package/src/plugins/builtin/chat/attachments/files.ts +45 -0
- package/src/plugins/builtin/chat/attachments/model.ts +164 -0
- package/src/plugins/builtin/chat/attachments/terminal.tsx +72 -0
- package/src/plugins/builtin/chat/attachments/transfer.ts +165 -0
- package/src/plugins/builtin/chat/content/channel-navigation.ts +13 -12
- package/src/plugins/builtin/chat/content/composer-runtime.ts +25 -4
- package/src/plugins/builtin/chat/content/composer.tsx +46 -4
- package/src/plugins/builtin/chat/content/footer.tsx +46 -8
- package/src/plugins/builtin/chat/content/index.tsx +263 -62
- package/src/plugins/builtin/chat/content/layout-metrics.ts +10 -2
- package/src/plugins/builtin/chat/content/open-targets.ts +17 -3
- package/src/plugins/builtin/chat/content/scroll.ts +7 -1
- package/src/plugins/builtin/chat/content/shortcuts.ts +36 -11
- package/src/plugins/builtin/chat/content/snapshot.ts +3 -0
- package/src/plugins/builtin/chat/content/transcript.tsx +17 -1
- package/src/plugins/builtin/chat/content/types.ts +7 -0
- package/src/plugins/builtin/chat/controller/attachments.ts +213 -0
- package/src/plugins/builtin/chat/controller/connections.ts +3 -1
- package/src/plugins/builtin/chat/controller/index.ts +114 -2
- package/src/plugins/builtin/chat/controller/lifecycle.ts +9 -0
- package/src/plugins/builtin/chat/controller/messages.ts +35 -2
- package/src/plugins/builtin/chat/controller/send.ts +128 -25
- package/src/plugins/builtin/chat/controller/state.ts +12 -1
- package/src/plugins/builtin/chat/controller/utils.ts +7 -5
- package/src/plugins/builtin/chat/controller/view.ts +2 -0
- package/src/plugins/builtin/chat/index.tsx +21 -0
- package/src/plugins/builtin/chat/layout.ts +9 -4
- package/src/plugins/builtin/chat/message/desktop.tsx +55 -20
- package/src/plugins/builtin/chat/message/header.tsx +30 -5
- package/src/plugins/builtin/chat/message/inline-tokens.tsx +9 -0
- package/src/plugins/builtin/chat/message/pending-send.ts +35 -0
- package/src/plugins/builtin/chat/message/profile-popover.tsx +5 -1
- package/src/plugins/builtin/chat/message/render-state.ts +12 -2
- package/src/plugins/builtin/chat/message/terminal.tsx +51 -4
- package/src/plugins/builtin/chat/message/types.ts +6 -1
- package/src/plugins/builtin/chat/pane-state.ts +59 -1
- package/src/plugins/builtin/chat/profile-popover.ts +50 -1
- package/src/plugins/builtin/chat/sidebar.tsx +8 -3
- package/src/plugins/builtin/chat/status-widget.tsx +29 -12
- package/src/plugins/builtin/chat/unread-inbox-pane.tsx +143 -0
- package/src/plugins/builtin/chat/unread-inbox.ts +91 -0
- package/src/plugins/builtin/clinical-trials/client.ts +237 -0
- package/src/plugins/builtin/clinical-trials/index.tsx +74 -0
- package/src/plugins/builtin/clinical-trials/pane.tsx +225 -0
- package/src/plugins/builtin/clinical-trials/types.ts +2 -0
- package/src/plugins/builtin/cloud/askg/controller.ts +37 -6
- package/src/plugins/builtin/cloud/askg/executor.ts +59 -44
- package/src/plugins/builtin/cloud/askg/host.ts +8 -1
- package/src/plugins/builtin/cloud/askg/manifest.ts +29 -2
- package/src/plugins/builtin/cloud/askg/model.ts +47 -13
- package/src/plugins/builtin/cloud/askg/notes.ts +100 -0
- package/src/plugins/builtin/cloud/askg/pane.tsx +50 -14
- package/src/plugins/builtin/cloud/askg/protocol.ts +39 -1
- package/src/plugins/builtin/cloud/askg/result-budget.ts +156 -0
- package/src/plugins/builtin/cloud/askg/user-data.ts +89 -0
- package/src/plugins/builtin/cloud/auth-actions.tsx +55 -31
- package/src/plugins/builtin/cloud/plugin.tsx +4 -1
- package/src/plugins/builtin/cloud/team/pane-sections.tsx +10 -1
- package/src/plugins/builtin/cloud/team/pane.tsx +3 -2
- package/src/plugins/builtin/cloud/thesis/board-pane.tsx +2 -2
- package/src/plugins/builtin/cloud/thesis/detail.tsx +1 -1
- package/src/plugins/builtin/cloud/thesis/ticker-tab.tsx +2 -2
- package/src/plugins/builtin/cloud/trial-offer-status-widget.tsx +202 -0
- package/src/plugins/builtin/cloud/upgrade-command.ts +1 -1
- package/src/plugins/builtin/cloud/upgrade-dialog.tsx +29 -3
- package/src/plugins/builtin/cloud/upgrade-status-widget.tsx +1 -1
- package/src/plugins/builtin/cloud-tweets/table.tsx +1 -1
- package/src/plugins/builtin/comment-letters/client.ts +342 -0
- package/src/plugins/builtin/comment-letters/index.tsx +74 -0
- package/src/plugins/builtin/comment-letters/pane.tsx +295 -0
- package/src/plugins/builtin/comment-letters/types.ts +43 -0
- package/src/plugins/builtin/company-attention/app-rank.tsx +79 -0
- package/src/plugins/builtin/company-attention/client.ts +69 -0
- package/src/plugins/builtin/company-attention/evidence.ts +45 -0
- package/src/plugins/builtin/company-attention/headless.ts +47 -0
- package/src/plugins/builtin/company-attention/index.tsx +30 -0
- package/src/plugins/builtin/company-attention/model.ts +129 -0
- package/src/plugins/builtin/company-attention/pane.tsx +183 -0
- package/src/plugins/builtin/company-kpis/client.ts +92 -0
- package/src/plugins/builtin/company-kpis/headless.ts +32 -0
- package/src/plugins/builtin/company-kpis/index.tsx +26 -0
- package/src/plugins/builtin/company-kpis/model.ts +124 -0
- package/src/plugins/builtin/company-kpis/pane.tsx +226 -0
- package/src/plugins/builtin/company-kpis/related.ts +11 -0
- package/src/plugins/builtin/company-kpis/screenshot-evidence.ts +44 -0
- package/src/plugins/builtin/composite-plugins.ts +34 -0
- package/src/plugins/builtin/correlation/history.ts +4 -1
- package/src/plugins/builtin/correlation/index.tsx +139 -80
- package/src/plugins/builtin/correlation/matrix/pair-chart.tsx +48 -0
- package/src/plugins/builtin/correlation/matrix/selection.ts +77 -0
- package/src/plugins/builtin/correlation/relationship/model.ts +2 -2
- package/src/plugins/builtin/cpi/client.ts +66 -0
- package/src/plugins/builtin/cpi/headless.ts +78 -0
- package/src/plugins/builtin/cpi/index.tsx +31 -0
- package/src/plugins/builtin/cpi/model.ts +198 -0
- package/src/plugins/builtin/cpi/pane.tsx +157 -0
- package/src/plugins/builtin/credit-documents/client.ts +99 -0
- package/src/plugins/builtin/credit-documents/detail.tsx +109 -0
- package/src/plugins/builtin/credit-documents/evidence.ts +64 -0
- package/src/plugins/builtin/credit-documents/gauge.tsx +55 -0
- package/src/plugins/builtin/credit-documents/headless.ts +40 -0
- package/src/plugins/builtin/credit-documents/index.tsx +19 -0
- package/src/plugins/builtin/credit-documents/model.ts +336 -0
- package/src/plugins/builtin/credit-documents/pane.tsx +185 -0
- package/src/plugins/builtin/custom-view/view-spec.ts +14 -2
- package/src/plugins/builtin/debt-maturities/pane.tsx +1 -0
- package/src/plugins/builtin/dividend-yield/pane.tsx +1 -1
- package/src/plugins/builtin/doe/client.ts +73 -0
- package/src/plugins/builtin/doe/headless.ts +93 -0
- package/src/plugins/builtin/doe/index.tsx +41 -0
- package/src/plugins/builtin/doe/model.ts +215 -0
- package/src/plugins/builtin/doe/pane.tsx +148 -0
- package/src/plugins/builtin/doe/range-bar.tsx +45 -0
- package/src/plugins/builtin/earnings/board.tsx +3 -0
- package/src/plugins/builtin/earnings/index.tsx +2 -0
- package/src/plugins/builtin/earnings-calls/pane.tsx +7 -1
- package/src/plugins/builtin/earnings-calls/transcript-view.tsx +7 -7
- package/src/plugins/builtin/earnings-ripple/client.ts +60 -0
- package/src/plugins/builtin/earnings-ripple/headless.ts +35 -0
- package/src/plugins/builtin/earnings-ripple/index.tsx +35 -0
- package/src/plugins/builtin/earnings-ripple/model.ts +98 -0
- package/src/plugins/builtin/earnings-ripple/pane.tsx +103 -0
- package/src/plugins/builtin/equity-screener/client.ts +1 -1
- package/src/plugins/builtin/equity-screener/criterion-editor.tsx +1 -1
- package/src/plugins/builtin/equity-screener/model.ts +74 -9
- package/src/plugins/builtin/equity-screener/pane.tsx +2 -0
- package/src/plugins/builtin/estimate-revisions/pane.tsx +3 -0
- package/src/plugins/builtin/executives/pane.tsx +7 -5
- package/src/plugins/builtin/exposure/charts.tsx +66 -0
- package/src/plugins/builtin/exposure/client.ts +53 -0
- package/src/plugins/builtin/exposure/drivers.ts +29 -0
- package/src/plugins/builtin/exposure/editor.tsx +61 -0
- package/src/plugins/builtin/exposure/evidence.ts +39 -0
- package/src/plugins/builtin/exposure/headless.ts +51 -0
- package/src/plugins/builtin/exposure/holdings.ts +56 -0
- package/src/plugins/builtin/exposure/index.tsx +13 -0
- package/src/plugins/builtin/exposure/model.ts +104 -0
- package/src/plugins/builtin/exposure/pane.tsx +247 -0
- package/src/plugins/builtin/fear-greed/charts.tsx +1 -1
- package/src/plugins/builtin/fear-greed/pane.tsx +2 -9
- package/src/plugins/builtin/filing-events/pane.tsx +2 -1
- package/src/plugins/builtin/gpu/board.tsx +163 -0
- package/src/plugins/builtin/gpu/changes.tsx +94 -0
- package/src/plugins/builtin/gpu/client.ts +130 -0
- package/src/plugins/builtin/gpu/equities.tsx +112 -0
- package/src/plugins/builtin/gpu/headless.ts +67 -0
- package/src/plugins/builtin/gpu/history.tsx +140 -0
- package/src/plugins/builtin/gpu/index.tsx +18 -0
- package/src/plugins/builtin/gpu/ladder.tsx +127 -0
- package/src/plugins/builtin/gpu/model.ts +317 -0
- package/src/plugins/builtin/gpu/pane.tsx +63 -0
- package/src/plugins/builtin/help/index.tsx +19 -2
- package/src/plugins/builtin/holders/pane.tsx +5 -9
- package/src/plugins/builtin/insider/detail.tsx +119 -0
- package/src/plugins/builtin/insider/display.ts +221 -0
- package/src/plugins/builtin/insider/headless.ts +24 -3
- package/src/plugins/builtin/insider/index.tsx +206 -108
- package/src/plugins/builtin/insider/insider-data.ts +31 -3
- package/src/plugins/builtin/insider/model.ts +53 -4
- package/src/plugins/builtin/insider/table-model.ts +226 -0
- package/src/plugins/builtin/insider/table.tsx +79 -0
- package/src/plugins/builtin/iv-history/screen-pane.tsx +1 -1
- package/src/plugins/builtin/jobs/pane.tsx +14 -7
- package/src/plugins/builtin/kelly-sizer/pane.tsx +1 -1
- package/src/plugins/builtin/macro-day/client.ts +50 -0
- package/src/plugins/builtin/macro-day/headless.ts +51 -0
- package/src/plugins/builtin/macro-day/index.tsx +21 -0
- package/src/plugins/builtin/macro-day/model.ts +137 -0
- package/src/plugins/builtin/macro-day/pane.tsx +118 -0
- package/src/plugins/builtin/macro-day/releases.ts +58 -0
- package/src/plugins/builtin/market-halts/model.ts +30 -17
- package/src/plugins/builtin/market-halts/pane.tsx +15 -21
- package/src/plugins/builtin/market-heatmap/data.ts +1 -1
- package/src/plugins/builtin/market-heatmap/index.tsx +198 -50
- package/src/plugins/builtin/market-heatmap/portfolio.ts +220 -0
- package/src/plugins/builtin/market-movers/index.tsx +1 -0
- package/src/plugins/builtin/market-movers/session-body.tsx +5 -2
- package/src/plugins/builtin/mna/distress/client.ts +326 -0
- package/src/plugins/builtin/mna/distress/detail.tsx +247 -0
- package/src/plugins/builtin/mna/distress/headless.ts +257 -0
- package/src/plugins/builtin/mna/distress/model.ts +427 -0
- package/src/plugins/builtin/mna/distress/pane.tsx +606 -0
- package/src/plugins/builtin/mna/index.tsx +15 -0
- package/src/plugins/builtin/mna/pane.tsx +42 -1
- package/src/plugins/builtin/news/index.tsx +62 -16
- package/src/plugins/builtin/news/wire/filter-articles.ts +54 -0
- package/src/plugins/builtin/news/wire/index.tsx +37 -3
- package/src/plugins/builtin/news/wire/industry-pane.tsx +29 -13
- package/src/plugins/builtin/news/wire/mutes.ts +253 -0
- package/src/plugins/builtin/news/wire/news/command-bar-search.ts +117 -0
- package/src/plugins/builtin/news/wire/news/footer.ts +4 -0
- package/src/plugins/builtin/news/wire/news/list-search.ts +34 -0
- package/src/plugins/builtin/news/wire/news/pop-out.tsx +158 -0
- package/src/plugins/builtin/news/wire/news/preset-pane.tsx +64 -19
- package/src/plugins/builtin/openfda/client.ts +300 -0
- package/src/plugins/builtin/openfda/index.tsx +71 -0
- package/src/plugins/builtin/openfda/pane.tsx +382 -0
- package/src/plugins/builtin/openfda/types.ts +76 -0
- package/src/plugins/builtin/options/footer.ts +1 -0
- package/src/plugins/builtin/options/view.tsx +1 -1
- package/src/plugins/builtin/options-calculator/pane.tsx +0 -1
- package/src/plugins/builtin/options-positioning/index.tsx +4 -2
- package/src/plugins/builtin/options-positioning/pane.tsx +1 -1
- package/src/plugins/builtin/pe-band/client.ts +61 -0
- package/src/plugins/builtin/pe-band/headless.ts +51 -0
- package/src/plugins/builtin/pe-band/index.tsx +20 -0
- package/src/plugins/builtin/pe-band/model.ts +267 -0
- package/src/plugins/builtin/pe-band/pane.tsx +159 -0
- package/src/plugins/builtin/perps/client.ts +66 -0
- package/src/plugins/builtin/perps/equity-row.tsx +28 -0
- package/src/plugins/builtin/perps/headless.ts +34 -0
- package/src/plugins/builtin/perps/index.tsx +14 -0
- package/src/plugins/builtin/perps/model.ts +58 -0
- package/src/plugins/builtin/perps/pane.tsx +185 -0
- package/src/plugins/builtin/plugin-marketplace/pane.tsx +0 -1
- package/src/plugins/builtin/portfolio-list/cli/render.ts +177 -87
- package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +6 -20
- package/src/plugins/builtin/portfolio-list/command-bar.ts +6 -2
- package/src/plugins/builtin/portfolio-list/headless.ts +237 -0
- package/src/plugins/builtin/portfolio-list/index.tsx +2 -0
- package/src/plugins/builtin/portfolio-list/mutations.ts +70 -1
- package/src/plugins/builtin/portfolio-list/pane/data.ts +17 -0
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +88 -5
- package/src/plugins/builtin/portfolio-list/pane/remove-ticker.ts +85 -0
- package/src/plugins/builtin/portfolio-list/pane/streaming.ts +18 -12
- package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +6 -0
- package/src/plugins/builtin/power/client.ts +100 -0
- package/src/plugins/builtin/power/detail.tsx +82 -0
- package/src/plugins/builtin/power/evidence.ts +56 -0
- package/src/plugins/builtin/power/generation.tsx +37 -0
- package/src/plugins/builtin/power/headless.ts +43 -0
- package/src/plugins/builtin/power/index.tsx +16 -0
- package/src/plugins/builtin/power/model.ts +89 -0
- package/src/plugins/builtin/power/pane.tsx +209 -0
- package/src/plugins/builtin/power/query.ts +25 -0
- package/src/plugins/builtin/relative-rotation/pane.tsx +3 -3
- package/src/plugins/builtin/research/analyst-pane.tsx +1 -1
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +13 -4
- package/src/plugins/builtin/research/equity-diagnostic-pane.tsx +11 -9
- package/src/plugins/builtin/research-search/pane.tsx +21 -7
- package/src/plugins/builtin/revenue-breakdown/pane.tsx +1 -1
- package/src/plugins/builtin/reverse-dcf/client.ts +35 -0
- package/src/plugins/builtin/reverse-dcf/headless.ts +44 -0
- package/src/plugins/builtin/reverse-dcf/index.tsx +20 -0
- package/src/plugins/builtin/reverse-dcf/model.ts +87 -0
- package/src/plugins/builtin/reverse-dcf/pane.tsx +107 -0
- package/src/plugins/builtin/risk-factors/pane.tsx +6 -5
- package/src/plugins/builtin/scanner/denied.tsx +4 -2
- package/src/plugins/builtin/scanner/feed.ts +1 -0
- package/src/plugins/builtin/scanner/flow-pane.tsx +3 -2
- package/src/plugins/builtin/scanner/hilo-pane.tsx +1 -1
- package/src/plugins/builtin/seasonality/client.ts +4 -1
- package/src/plugins/builtin/sec/command-bar-search.ts +217 -0
- package/src/plugins/builtin/sec/forms.ts +54 -0
- package/src/plugins/builtin/sec/headless.ts +31 -5
- package/src/plugins/builtin/sec/index.tsx +67 -11
- package/src/plugins/builtin/sec/model.ts +35 -5
- package/src/plugins/builtin/sectors/headless.ts +1 -0
- package/src/plugins/builtin/sectors/index.tsx +72 -26
- package/src/plugins/builtin/shared/cloud-upgrade.ts +143 -39
- package/src/plugins/builtin/shared/pro-feature-wall.tsx +8 -4
- package/src/plugins/builtin/shared/research-cells.tsx +107 -0
- package/src/plugins/builtin/shared/series-list-detail.tsx +5 -1
- package/src/plugins/builtin/shared/ticker-request.ts +1 -1
- package/src/plugins/builtin/shared/wall-teaser-catalog.ts +80 -0
- package/src/plugins/builtin/shared/wall-teaser.tsx +192 -0
- package/src/plugins/builtin/shared/wall-view-lifecycle.ts +43 -0
- package/src/plugins/builtin/short-interest/index.tsx +31 -0
- package/src/plugins/builtin/short-interest/watch-client.ts +70 -0
- package/src/plugins/builtin/short-interest/watch-headless.ts +49 -0
- package/src/plugins/builtin/short-interest/watch-model.ts +185 -0
- package/src/plugins/builtin/short-interest/watch-pane.tsx +169 -0
- package/src/plugins/builtin/short-volume/pane.tsx +1 -1
- package/src/plugins/builtin/social-mentions/pane.tsx +1 -1
- package/src/plugins/builtin/supply-chain/client.ts +104 -0
- package/src/plugins/builtin/supply-chain/disclosure-quote.tsx +17 -0
- package/src/plugins/builtin/supply-chain/evidence.ts +88 -0
- package/src/plugins/builtin/supply-chain/flow-layout.ts +133 -0
- package/src/plugins/builtin/supply-chain/flow.tsx +323 -0
- package/src/plugins/builtin/supply-chain/graph-client.ts +83 -0
- package/src/plugins/builtin/supply-chain/graph-evidence.ts +25 -0
- package/src/plugins/builtin/supply-chain/graph-model.ts +45 -0
- package/src/plugins/builtin/supply-chain/graph-pane.tsx +218 -0
- package/src/plugins/builtin/supply-chain/graph.tsx +163 -0
- package/src/plugins/builtin/supply-chain/headless.ts +105 -0
- package/src/plugins/builtin/supply-chain/index.tsx +17 -0
- package/src/plugins/builtin/supply-chain/model.ts +145 -0
- package/src/plugins/builtin/supply-chain/pane.tsx +276 -0
- package/src/plugins/builtin/supply-chain/row-evidence.tsx +96 -0
- package/src/plugins/builtin/supply-chain/trust.ts +34 -0
- package/src/plugins/builtin/themes/client.ts +39 -0
- package/src/plugins/builtin/themes/headless.ts +38 -0
- package/src/plugins/builtin/themes/model.ts +92 -0
- package/src/plugins/builtin/themes/pane.tsx +125 -0
- package/src/plugins/builtin/thirteenf/pane.tsx +6 -15
- package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +5 -6
- package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +201 -0
- package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +327 -0
- package/src/plugins/builtin/ticker-detail/financials/period-end-history.ts +5 -2
- package/src/plugins/builtin/ticker-detail/financials/ratios.ts +60 -12
- package/src/plugins/builtin/ticker-detail/financials/tab.tsx +2 -1
- package/src/plugins/builtin/ticker-detail/headless.ts +7 -2
- package/src/plugins/builtin/ticker-detail/index.tsx +22 -0
- package/src/plugins/builtin/ticker-detail/overview/components.tsx +53 -30
- package/src/plugins/builtin/ticker-detail/overview/pane.tsx +2 -0
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +112 -47
- package/src/plugins/builtin/ticker-detail/pane.tsx +50 -6
- package/src/plugins/builtin/ticker-detail/quote-monitor/card.tsx +21 -42
- package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +3 -0
- package/src/plugins/builtin/time-sales/pane.tsx +1 -1
- package/src/plugins/builtin/world-indices/indices.ts +1 -0
- package/src/plugins/catalog-browser.ts +40 -0
- package/src/plugins/catalog-manifest.ts +3 -0
- package/src/plugins/catalog-ui.ts +6 -0
- package/src/plugins/current-target.ts +0 -9
- package/src/public/__snapshots__/public-api.test.ts.snap +1 -0
- package/src/renderers/browser/cloud-transport.ts +66 -1
- package/src/renderers/browser/main.tsx +2 -0
- package/src/renderers/dom/data-table/row.tsx +2 -0
- package/src/renderers/dom/desktop/controls.tsx +38 -25
- package/src/renderers/dom/desktop/icons.tsx +8 -0
- package/src/renderers/dom/host/chart-surface.tsx +36 -2
- package/src/renderers/dom/host/focus-scope.ts +11 -1
- package/src/renderers/dom/styles.css +28 -0
- package/src/renderers/electrobun/view/backend-rpc.ts +3 -2
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -1
- package/src/renderers/electrobun/view/http-fetch.ts +2 -0
- package/src/renderers/electrobun/view/main.tsx +3 -1
- package/src/renderers/electrobun/view/rpc-timeout.ts +59 -0
- package/src/renderers/opentui/start.tsx +3 -0
- package/src/shares/api.ts +3 -1
- package/src/sources/gloomberb-cloud/index.ts +47 -13
- package/src/sources/history-result.ts +1 -0
- package/src/sources/history-retention.ts +16 -0
- package/src/sources/provider-router/history.ts +4 -2
- package/src/sources/sec-edgar/identity.ts +36 -0
- package/src/sources/sec-edgar.ts +1 -34
- package/src/state/app/context/index.tsx +8 -0
- package/src/sync/core-contributors.ts +20 -2
- package/src/telemetry/attention-counts.ts +164 -0
- package/src/telemetry/live-config.ts +7 -0
- package/src/test-support/rpc-loopback.ts +7 -3
- package/src/test-support/shell-pane-keys.tsx +34 -0
- package/src/tickers/instrument-kind.ts +12 -6
- package/src/tickers/open-target.ts +1 -1
- package/src/tickers/search/asset-classes.ts +91 -0
- package/src/tickers/search/index.ts +62 -15
- package/src/tickers/search/ranking.ts +22 -3
- package/src/tickers/search/upsert.ts +4 -1
- package/src/time-series/live-bars.ts +8 -3
- package/src/time-series/resolve.ts +224 -17
- package/src/time-series/spec.ts +1 -0
- package/src/time-series/types.ts +9 -1
- package/src/types/config.ts +23 -1
- package/src/types/data-provider.ts +2 -0
- package/src/types/headless.ts +17 -0
- package/src/types/price-history.ts +2 -0
- package/src/ui/host.tsx +6 -0
- package/src/utils/double-escape-close.ts +20 -0
- package/src/utils/exchanges.ts +1 -0
- package/src/utils/html-entities.ts +15 -0
- package/src/utils/http-proxy-response.ts +44 -7
- package/src/utils/plugin-proxy-hosts.json +3 -0
- package/src/utils/price-history.ts +35 -1
- package/src/utils/sec.ts +21 -2
- package/src/utils/text-wrap.ts +13 -8
- package/src/utils/zoned-date-time.ts +67 -0
|
@@ -18,9 +18,10 @@ const CLOUD_UPGRADE_URL = "https://gloom.sh/cloud?upgrade=pro";
|
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* The renderer host only exists inside React, so UI that uses it publishes an
|
|
21
|
-
* opener here for the command bar, which runs outside the tree.
|
|
21
|
+
* opener here for the command bar, which runs outside the tree. Every mounted
|
|
22
|
+
* prompt publishes one, so a pane closing never leaves the command without.
|
|
22
23
|
*/
|
|
23
|
-
|
|
24
|
+
const cloudUpgradeOpeners = new Set<(options?: unknown) => void>();
|
|
24
25
|
|
|
25
26
|
/**
|
|
26
27
|
* Signed-out users get the public Cloud page. Signed-in free accounts go
|
|
@@ -30,72 +31,171 @@ let cloudUpgradeOpener: (() => void) | null = null;
|
|
|
30
31
|
* re-buys a subscription they already hold. Both URLs are account-bound, so no
|
|
31
32
|
* session handoff is needed.
|
|
32
33
|
*/
|
|
33
|
-
|
|
34
|
+
interface CloudUpgradeOptions {
|
|
35
|
+
/**
|
|
36
|
+
* The prompt the upgrade came from, sent with `upgrade_intent` so each one's
|
|
37
|
+
* conversion can be read: a short id in the shape of a tab id (`srch-wall`,
|
|
38
|
+
* `status-widget`), never the prompt's text or anything the user typed.
|
|
39
|
+
*/
|
|
40
|
+
placement?: string;
|
|
34
41
|
/** Billing interval for a fresh checkout; ignored when the account already has Pro. */
|
|
35
42
|
interval?: "month" | "year";
|
|
36
43
|
/** False when the upgrade sheet already recorded the intent on open. */
|
|
37
44
|
recordIntent?: boolean;
|
|
38
45
|
/** False when the caller already made the pitch, like onboarding's Pro step. */
|
|
39
46
|
sheet?: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Called once checkout or the billing portal starts opening, after the sheet;
|
|
49
|
+
* never for a press ignored as a repeat.
|
|
50
|
+
*/
|
|
51
|
+
onOpening?: () => void;
|
|
40
52
|
}
|
|
41
53
|
|
|
42
|
-
|
|
43
|
-
|
|
54
|
+
function recordUpgradeIntent(placement: string | undefined): void {
|
|
55
|
+
recordResearchActivity("upgrade_intent", undefined, undefined, { placement });
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* The page an upgrade opens: Stripe checkout for a free account, the billing
|
|
60
|
+
* portal for one that has Pro, and the public Cloud page when signed out or
|
|
61
|
+
* when neither can be created.
|
|
62
|
+
*/
|
|
63
|
+
type CloudUpgradePage = "checkout" | "portal" | "cloud";
|
|
64
|
+
|
|
65
|
+
/** How long another open of the same page is ignored once one has opened. */
|
|
66
|
+
const CLOUD_UPGRADE_REOPEN_MS = 3_000;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* How long a page may stay opening before another press tries again. The
|
|
70
|
+
* checkout and portal requests have no deadline of their own, and one that
|
|
71
|
+
* hangs must not block the page until the app restarts.
|
|
72
|
+
*/
|
|
73
|
+
const CLOUD_UPGRADE_PENDING_MS = 30_000;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* When each page may open again: not while its URL is being created or
|
|
77
|
+
* opened (up to {@link CLOUD_UPGRADE_PENDING_MS}), and not for
|
|
78
|
+
* {@link CLOUD_UPGRADE_REOPEN_MS} after it opened. Every
|
|
79
|
+
* open creates a Stripe session and a browser tab, and a held Enter repeats a
|
|
80
|
+
* press many times a second. Keyed by page, so a checkout that just opened
|
|
81
|
+
* never swallows the billing portal or the Cloud page.
|
|
82
|
+
*/
|
|
83
|
+
const cloudUpgradeBlockedUntil = new Map<CloudUpgradePage, number>();
|
|
84
|
+
|
|
85
|
+
function currentCloudUpgradePage(): CloudUpgradePage {
|
|
86
|
+
if (!apiClient.isSignedIn()) return "cloud";
|
|
87
|
+
return resolvePlanAccess(apiClient.getCurrentUser()).hasProAccess ? "portal" : "checkout";
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function isCloudUpgradeBlocked(page: CloudUpgradePage): boolean {
|
|
91
|
+
return (cloudUpgradeBlockedUntil.get(page) ?? 0) > Date.now();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Runs `open` unless `page` is already opening or opened moments ago. A failed
|
|
96
|
+
* open releases the page at once, so a retry works, and rethrows. A call that
|
|
97
|
+
* outlived its pending window leaves the block of the call after it alone.
|
|
98
|
+
*/
|
|
99
|
+
async function openCloudUpgradePage(page: CloudUpgradePage, open: () => Promise<void>): Promise<void> {
|
|
100
|
+
if (isCloudUpgradeBlocked(page)) return;
|
|
101
|
+
const pending = Date.now() + CLOUD_UPGRADE_PENDING_MS;
|
|
102
|
+
cloudUpgradeBlockedUntil.set(page, pending);
|
|
103
|
+
const settle = (until: number | null) => {
|
|
104
|
+
if (cloudUpgradeBlockedUntil.get(page) !== pending) return;
|
|
105
|
+
if (until === null) cloudUpgradeBlockedUntil.delete(page);
|
|
106
|
+
else cloudUpgradeBlockedUntil.set(page, until);
|
|
107
|
+
};
|
|
108
|
+
try {
|
|
109
|
+
await open();
|
|
110
|
+
} catch (error) {
|
|
111
|
+
settle(null);
|
|
112
|
+
throw error;
|
|
113
|
+
}
|
|
114
|
+
settle(Date.now() + CLOUD_UPGRADE_REOPEN_MS);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** Forgets every recent open, so one test's checkout does not swallow the next test's. */
|
|
118
|
+
export function resetCloudUpgradeGuardForTests(): void {
|
|
119
|
+
cloudUpgradeBlockedUntil.clear();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async function resolveCloudUpgradeUrl(page: CloudUpgradePage, options: CloudUpgradeOptions): Promise<string> {
|
|
44
123
|
const returnTo = getCurrentPluginTarget() === "web" ? window.location.href : undefined;
|
|
45
|
-
if (
|
|
46
|
-
const { url } =
|
|
124
|
+
if (page === "cloud") return researchUpgradeUrl(returnTo);
|
|
125
|
+
const { url } = page === "portal"
|
|
47
126
|
? await apiClient.createBillingPortal()
|
|
48
127
|
: await apiClient.createCloudCheckout(returnTo, options.interval ?? "month");
|
|
49
128
|
return url;
|
|
50
129
|
}
|
|
51
130
|
|
|
52
|
-
/** Opens checkout
|
|
53
|
-
|
|
131
|
+
/** Opens checkout, the billing portal or the Cloud page in the user's browser. */
|
|
132
|
+
async function openCloudUpgrade(
|
|
54
133
|
rendererHost: Pick<RendererHost, "openExternal">,
|
|
55
|
-
|
|
134
|
+
page: CloudUpgradePage,
|
|
135
|
+
options: CloudUpgradeOptions,
|
|
56
136
|
): Promise<void> {
|
|
57
|
-
await rendererHost.openExternal(await resolveCloudUpgradeUrl(options));
|
|
137
|
+
await rendererHost.openExternal(await resolveCloudUpgradeUrl(page, options));
|
|
58
138
|
}
|
|
59
139
|
|
|
60
|
-
/**
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
140
|
+
/**
|
|
141
|
+
* Opens the checkout page when any cloud UI has published an opener, counted
|
|
142
|
+
* under `placement` rather than the UI that published it.
|
|
143
|
+
*/
|
|
144
|
+
export function openCloudUpgradeUrl(placement: string): boolean {
|
|
145
|
+
const opener = [...cloudUpgradeOpeners].at(-1);
|
|
146
|
+
if (!opener) return false;
|
|
147
|
+
opener({ placement });
|
|
64
148
|
return true;
|
|
65
149
|
}
|
|
66
150
|
|
|
151
|
+
const CLOUD_UPGRADE_OPTION_KEYS: ReadonlyArray<keyof CloudUpgradeOptions> = ["placement", "interval", "recordIntent", "sheet", "onOpening"];
|
|
152
|
+
|
|
153
|
+
/** A press event carries none of these keys, so it never reads as options. */
|
|
67
154
|
function isCloudUpgradeOptions(value: unknown): value is CloudUpgradeOptions {
|
|
68
|
-
return !!value && typeof value === "object" &&
|
|
155
|
+
return !!value && typeof value === "object" && CLOUD_UPGRADE_OPTION_KEYS.some((key) => key in value);
|
|
69
156
|
}
|
|
70
157
|
|
|
71
158
|
/**
|
|
72
|
-
* Opens the Pro checkout page in the user's browser
|
|
73
|
-
*
|
|
74
|
-
*
|
|
159
|
+
* Opens the Pro checkout page in the user's browser, counting the intent under
|
|
160
|
+
* `placement` (see {@link CloudUpgradeOptions.placement}). The action doubles
|
|
161
|
+
* as a press handler for buttons and footer segments, which hand it their
|
|
162
|
+
* event, so only an explicit options object changes the checkout. It settles
|
|
163
|
+
* once checkout has opened or the person backed out of the sheet. A call while
|
|
164
|
+
* the same page is opening, or for a few seconds after it opened, is ignored:
|
|
165
|
+
* a held Enter would otherwise open a checkout per keypress.
|
|
75
166
|
*
|
|
76
167
|
* A signed-in account without Pro sees the upgrade sheet first (what Pro adds,
|
|
77
168
|
* what today costs), and checkout opens only once they choose to go on.
|
|
78
169
|
* Signed-out users get the public Cloud page and Pro accounts the billing
|
|
79
170
|
* portal, as before.
|
|
80
171
|
*/
|
|
81
|
-
export function useCloudUpgradeAction(): (options?: unknown) => void {
|
|
172
|
+
export function useCloudUpgradeAction(placement: string): (options?: unknown) => Promise<void> {
|
|
82
173
|
const rendererHost = useRendererHost();
|
|
83
174
|
// Null in isolated renders (tests, previews): checkout then opens directly.
|
|
84
175
|
const dialog = useOptionalDialog();
|
|
85
176
|
const viewport = useViewport();
|
|
86
177
|
const viewportWidthRef = useRef(viewport.width);
|
|
87
178
|
viewportWidthRef.current = viewport.width;
|
|
88
|
-
const openUpgrade = useCallback((options?: unknown) => {
|
|
89
|
-
const checkout = isCloudUpgradeOptions(options) ? options : {};
|
|
90
|
-
const openCheckout = (resolved: CloudUpgradeOptions) => {
|
|
91
|
-
|
|
179
|
+
const openUpgrade = useCallback(async (options?: unknown) => {
|
|
180
|
+
const checkout: CloudUpgradeOptions = { placement, ...(isCloudUpgradeOptions(options) ? options : {}) };
|
|
181
|
+
const openCheckout = async (resolved: CloudUpgradeOptions) => {
|
|
182
|
+
if (resolved.recordIntent !== false) recordUpgradeIntent(resolved.placement);
|
|
183
|
+
const page = currentCloudUpgradePage();
|
|
184
|
+
await openCloudUpgradePage(page, async () => {
|
|
185
|
+
resolved.onOpening?.();
|
|
186
|
+
await openCloudUpgrade(rendererHost, page, resolved);
|
|
187
|
+
}).catch(() => (
|
|
92
188
|
// Keep the Cloud page reachable when checkout cannot be created; a native
|
|
93
|
-
// session still rides along on the server's one-time handoff URL.
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
189
|
+
// session still rides along on the server's one-time handoff URL. Under
|
|
190
|
+
// the Cloud page's guard, so a retry that fails again moments later
|
|
191
|
+
// opens no second tab.
|
|
192
|
+
openCloudUpgradePage("cloud", async () => {
|
|
193
|
+
const url = await apiClient.createBrowserHandoff()
|
|
194
|
+
.then((handoff) => handoff.url)
|
|
195
|
+
.catch(() => CLOUD_UPGRADE_URL);
|
|
196
|
+
await rendererHost.openExternal(url);
|
|
197
|
+
})
|
|
198
|
+
)).catch(() => {});
|
|
99
199
|
};
|
|
100
200
|
if (
|
|
101
201
|
checkout.sheet === false ||
|
|
@@ -103,21 +203,22 @@ export function useCloudUpgradeAction(): (options?: unknown) => void {
|
|
|
103
203
|
!apiClient.isSignedIn() ||
|
|
104
204
|
resolvePlanAccess(apiClient.getCurrentUser()).hasProAccess
|
|
105
205
|
) {
|
|
106
|
-
openCheckout(checkout);
|
|
206
|
+
await openCheckout(checkout);
|
|
107
207
|
return;
|
|
108
208
|
}
|
|
109
|
-
|
|
110
|
-
|
|
209
|
+
recordUpgradeIntent(checkout.placement);
|
|
210
|
+
// Checkout is opening or just opened: a second sheet would lead nowhere.
|
|
211
|
+
if (isCloudUpgradeBlocked("checkout")) return;
|
|
212
|
+
const interval = await promptCloudUpgrade(dialog, {
|
|
111
213
|
interval: checkout.interval,
|
|
112
214
|
viewportWidth: viewportWidthRef.current,
|
|
113
|
-
}).then((interval) => {
|
|
114
|
-
if (interval) openCheckout({ interval, recordIntent: false });
|
|
115
215
|
});
|
|
116
|
-
|
|
216
|
+
if (interval) await openCheckout({ ...checkout, interval, recordIntent: false });
|
|
217
|
+
}, [dialog, placement, rendererHost]);
|
|
117
218
|
useEffect(() => {
|
|
118
|
-
|
|
219
|
+
cloudUpgradeOpeners.add(openUpgrade);
|
|
119
220
|
return () => {
|
|
120
|
-
|
|
221
|
+
cloudUpgradeOpeners.delete(openUpgrade);
|
|
121
222
|
};
|
|
122
223
|
}, [openUpgrade]);
|
|
123
224
|
return openUpgrade;
|
|
@@ -150,6 +251,8 @@ export interface CloudAccessFooterOptions {
|
|
|
150
251
|
/** Set false while the pane happens to show data that is not cloud-delayed. */
|
|
151
252
|
degraded?: boolean;
|
|
152
253
|
segmentId?: string;
|
|
254
|
+
/** The upgrade intent's placement id (see {@link CloudUpgradeOptions.placement}); the segment id when omitted. */
|
|
255
|
+
placement?: string;
|
|
153
256
|
}
|
|
154
257
|
|
|
155
258
|
export interface CloudAccessFooter {
|
|
@@ -175,10 +278,11 @@ export function useCloudAccessFooter({
|
|
|
175
278
|
degraded = true,
|
|
176
279
|
segmentId = "cloud-access",
|
|
177
280
|
shortcutScope,
|
|
281
|
+
placement = segmentId,
|
|
178
282
|
}: CloudAccessFooterOptions): CloudAccessFooter {
|
|
179
283
|
const language = useAppLanguage();
|
|
180
284
|
const access = usePlanAccess();
|
|
181
|
-
const openUpgrade = useCloudUpgradeAction();
|
|
285
|
+
const openUpgrade = useCloudUpgradeAction(placement);
|
|
182
286
|
const openPlan = useCloudPlanAction();
|
|
183
287
|
|
|
184
288
|
const showTrial = access.isTrialActive;
|
|
@@ -2,8 +2,11 @@ import { useCallback, useEffect, useState, type ReactNode } from "react";
|
|
|
2
2
|
import { ApiRequestError } from "../../../api-client/errors";
|
|
3
3
|
import { usePlanAccess } from "../../../api-client/plan-access";
|
|
4
4
|
import { ProWall, SignInWall } from "../cloud/auth-actions";
|
|
5
|
+
import { useBoundTicker } from "./ticker-request";
|
|
5
6
|
|
|
6
7
|
export interface ProFeatureWallCopy {
|
|
8
|
+
/** The upgrade intent's placement id, e.g. "risk-wall". */
|
|
9
|
+
placement: string;
|
|
7
10
|
/** Finishes "Sign in to …", e.g. "read risk factors". */
|
|
8
11
|
action: string;
|
|
9
12
|
/** The upgrade headline, e.g. "Risk factors are part of Gloom Cloud Pro." */
|
|
@@ -21,11 +24,12 @@ export type ReadGuard = <T>(read: Promise<T>) => Promise<T>;
|
|
|
21
24
|
* through `guard`, so a refusal from the server (a plan that ended while the
|
|
22
25
|
* app was open, an expired session) shows the same wall, not an error.
|
|
23
26
|
*/
|
|
24
|
-
export function useProFeatureWall(copy: ProFeatureWallCopy): {
|
|
27
|
+
export function useProFeatureWall(copy: ProFeatureWallCopy, size: { width: number; height: number }): {
|
|
25
28
|
wall: ReactNode;
|
|
26
29
|
guard: ReadGuard;
|
|
27
30
|
} {
|
|
28
31
|
const access = usePlanAccess();
|
|
32
|
+
const { symbol, exchange } = useBoundTicker();
|
|
29
33
|
const [refused, setRefused] = useState<number | null>(null);
|
|
30
34
|
// A refusal is about the plan the account had then; a new plan asks again.
|
|
31
35
|
useEffect(() => setRefused(null), [access.signedIn, access.emailVerified, access.hasProAccess]);
|
|
@@ -37,11 +41,11 @@ export function useProFeatureWall(copy: ProFeatureWallCopy): {
|
|
|
37
41
|
|
|
38
42
|
let wall: ReactNode = null;
|
|
39
43
|
if (!access.signedIn || refused === 401) {
|
|
40
|
-
wall = <SignInWall action={copy.action} />;
|
|
44
|
+
wall = <SignInWall placement={`${copy.placement.replace(/-wall$/, "")}-signin`} {...size} symbol={symbol} exchange={exchange} action={copy.action} />;
|
|
41
45
|
} else if (!access.emailVerified || refused === 403) {
|
|
42
|
-
wall = <SignInWall action={copy.action} needsVerification />;
|
|
46
|
+
wall = <SignInWall placement={`${copy.placement.replace(/-wall$/, "")}-signin`} {...size} symbol={symbol} exchange={exchange} action={copy.action} needsVerification />;
|
|
43
47
|
} else if (!access.hasProAccess || refused === 402) {
|
|
44
|
-
wall = <ProWall title={copy.title} message={copy.message} />;
|
|
48
|
+
wall = <ProWall placement={copy.placement} title={copy.title} message={copy.message} {...size} symbol={symbol} exchange={exchange} />;
|
|
45
49
|
}
|
|
46
50
|
return { wall, guard };
|
|
47
51
|
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import type { DataTableCell, DataTableColumn } from "../../../components";
|
|
2
|
+
import { SplitBar } from "../../../components/ui/split-bar";
|
|
3
|
+
import { blendHex } from "../../../theme/colors";
|
|
4
|
+
import type { ThemeColors } from "../../../theme/colors";
|
|
5
|
+
import { Box, Text, TextAttributes } from "../../../ui";
|
|
6
|
+
import { displayWidth } from "../../../utils/format";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Cells the research data panes share, so attention, hiring, awards, power and
|
|
10
|
+
* the rest read the same way: one muted placeholder, moves coloured by sign,
|
|
11
|
+
* a listing as its symbol with the venue quiet beside it, and a share as a
|
|
12
|
+
* length next to its number.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/** The one placeholder for a value the source does not give. */
|
|
16
|
+
const NO_VALUE = "--";
|
|
17
|
+
|
|
18
|
+
export const missingCell = (colors: ThemeColors): DataTableCell => ({ text: NO_VALUE, value: null, color: colors.textMuted });
|
|
19
|
+
|
|
20
|
+
/** A move or a change: green up, red down, quiet at zero. */
|
|
21
|
+
export function signedColor(value: number | null | undefined, colors: ThemeColors): string {
|
|
22
|
+
return value == null || value === 0 ? colors.textMuted : value > 0 ? colors.positive : colors.negative;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** `6758:JPX` reads as the symbol, with the venue after it in a quieter colour. */
|
|
26
|
+
export function listingCell(key: string | null | undefined, colors: ThemeColors, selected: boolean): DataTableCell {
|
|
27
|
+
if (!key) return missingCell(colors);
|
|
28
|
+
const at = key.indexOf(":");
|
|
29
|
+
const symbol = at > 0 ? key.slice(0, at) : key;
|
|
30
|
+
const venue = at > 0 ? key.slice(at + 1) : "";
|
|
31
|
+
return { text: key, content: <Box flexDirection="row" height={1} overflow="hidden">
|
|
32
|
+
<Text fg={selected ? colors.selectedText : colors.textBright} attributes={TextAttributes.BOLD}>{symbol}</Text>
|
|
33
|
+
{venue ? <Text fg={selected ? colors.selectedText : colors.textDim}>{` ${venue}`}</Text> : null}
|
|
34
|
+
</Box> };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* A share of a whole as its number and a bar measured against the largest row,
|
|
39
|
+
* so the eye compares lengths down the column. The bar gives way first in a
|
|
40
|
+
* narrow column; the number never does.
|
|
41
|
+
*/
|
|
42
|
+
export function shareCell(text: string, ratio: number | null, width: number, colors: ThemeColors, selected: boolean, desktop: boolean,
|
|
43
|
+
color = blendHex(colors.bg, colors.borderFocused, 0.6)): DataTableCell {
|
|
44
|
+
const textCells = displayWidth(text);
|
|
45
|
+
const barCells = width - textCells - 1;
|
|
46
|
+
if (ratio == null || !(ratio > 0) || barCells < 4) return { text, color: selected ? colors.selectedText : colors.text };
|
|
47
|
+
const fill = Math.max(0, Math.min(1, ratio));
|
|
48
|
+
const ink = selected ? colors.selectedText : color;
|
|
49
|
+
// The desktop draws the bar on a faint track; terminal cells draw the length alone, at half-cell steps,
|
|
50
|
+
// since a track of block cells would join the rows above and below into one wall.
|
|
51
|
+
const units = Math.max(1, Math.round(fill * barCells * 2));
|
|
52
|
+
return { text, content: <Box flexDirection="row" height={1} width={width} overflow="hidden" alignItems="center">
|
|
53
|
+
<Box width={barCells} flexShrink={0} flexDirection="row" alignItems="center">
|
|
54
|
+
{desktop ? <SplitBar width={barCells} parts={[{ id: "share", value: fill, color: ink }, { id: "rest", value: 1 - fill, color: blendHex(colors.bg, color, 0.2) }]} />
|
|
55
|
+
: <Text fg={ink}>{`${"█".repeat(Math.floor(units / 2))}${units % 2 ? "▌" : ""}`}</Text>}
|
|
56
|
+
</Box>
|
|
57
|
+
<Box flexGrow={1} justifyContent="flex-end"><Text fg={selected ? colors.selectedText : colors.text}>{` ${text}`}</Text></Box>
|
|
58
|
+
</Box> };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Parts of a whole as one bar, strongest part first. The desktop uses the kit
|
|
63
|
+
* bar; terminal cells step down from solid to light shade, so neighbouring
|
|
64
|
+
* rows read as separate bars rather than one block.
|
|
65
|
+
*/
|
|
66
|
+
export function PartsBar({ parts, width, desktop }: { parts: Array<{ id: string; value: number; color: string }>; width: number; desktop: boolean }) {
|
|
67
|
+
if (desktop) return <Box width={width} height={1} alignItems="center"><SplitBar width={width} parts={parts} /></Box>;
|
|
68
|
+
const total = parts.reduce((sum, part) => sum + Math.max(0, part.value), 0);
|
|
69
|
+
if (!(total > 0) || width <= 0) return <Text>{""}</Text>;
|
|
70
|
+
const glyphs = ["█", "▓", "▒", "░"];
|
|
71
|
+
let used = 0;
|
|
72
|
+
return <Box flexDirection="row" width={width} height={1} overflow="hidden">
|
|
73
|
+
{parts.map((part, index) => {
|
|
74
|
+
const cells = index === parts.length - 1 ? Math.max(0, width - used) : Math.round(Math.max(0, part.value) / total * width);
|
|
75
|
+
used += cells;
|
|
76
|
+
return part.value > 0 && cells > 0 ? <Text key={part.id} fg={part.color}>{(glyphs[index] ?? "░").repeat(cells)}</Text> : null;
|
|
77
|
+
})}
|
|
78
|
+
</Box>;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** A state word in its tone: the same status reads the same in every pane. */
|
|
82
|
+
export type StateTone = "positive" | "negative" | "warning" | "accent" | "muted" | "text";
|
|
83
|
+
export function toneColor(tone: StateTone, colors: ThemeColors): string {
|
|
84
|
+
return tone === "accent" ? colors.borderFocused : tone === "muted" ? colors.textMuted : tone === "text" ? colors.text : colors[tone];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** `ACTIVE_NOT_RECRUITING`, `active not recruiting` and `deadlineDate` all read as words. */
|
|
88
|
+
export function humanLabel(value: string): string {
|
|
89
|
+
const spaced = value.trim().replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").replace(/\s+/g, " ").toLowerCase();
|
|
90
|
+
return spaced.replace(/^./, (first) => first.toUpperCase()).replace(/\b(ai|us|uk|eu|fda|ema|sec|ftc|doj|ofac|usa)\b/gi, (word) => word.toUpperCase());
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Drops the columns whose cells read the same default on every row: a scope
|
|
95
|
+
* that is always "Project", a missing count that is always zero. A row that
|
|
96
|
+
* differs brings the column back; a uniform value that is not a default stays.
|
|
97
|
+
*/
|
|
98
|
+
export function withoutQuietColumns<T>(columns: DataTableColumn[], rows: readonly T[], read: (row: T, columnId: string) => unknown,
|
|
99
|
+
quiet: Readonly<Record<string, readonly string[]>>): DataTableColumn[] {
|
|
100
|
+
if (!rows.length) return columns;
|
|
101
|
+
return columns.filter((column) => {
|
|
102
|
+
const defaults = quiet[column.id];
|
|
103
|
+
if (!defaults) return true;
|
|
104
|
+
const first = String(read(rows[0]!, column.id) ?? "");
|
|
105
|
+
return !defaults.includes(first) || rows.some((row) => String(read(row, column.id) ?? "") !== first);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
useQueryBarSearch,
|
|
6
6
|
type DataTableColumn,
|
|
7
7
|
type DataTableSelectionChangeReason,
|
|
8
|
+
type QueryBarFilter,
|
|
8
9
|
type QueryBarView,
|
|
9
10
|
} from "../../../components";
|
|
10
11
|
import type { DataTableViewProps } from "../../../components/data-table/view";
|
|
@@ -127,6 +128,7 @@ export function SeriesListDetail<Row, Column extends DataTableColumn, R extends
|
|
|
127
128
|
focused,
|
|
128
129
|
listWidth: maxListWidth,
|
|
129
130
|
searchPlaceholder,
|
|
131
|
+
filters,
|
|
130
132
|
columns: buildColumns,
|
|
131
133
|
rows,
|
|
132
134
|
getRowId,
|
|
@@ -143,6 +145,8 @@ export function SeriesListDetail<Row, Column extends DataTableColumn, R extends
|
|
|
143
145
|
/** The table's width beside the detail. */
|
|
144
146
|
listWidth: number;
|
|
145
147
|
searchPlaceholder: string;
|
|
148
|
+
/** Choices beside the search that pick which series the list holds, such as a model. */
|
|
149
|
+
filters?: QueryBarFilter[];
|
|
146
150
|
columns: (width: number, stacked: boolean) => Column[];
|
|
147
151
|
/** Table rows for the visible items, with any section headers. */
|
|
148
152
|
rows: Row[];
|
|
@@ -170,7 +174,7 @@ export function SeriesListDetail<Row, Column extends DataTableColumn, R extends
|
|
|
170
174
|
|
|
171
175
|
return (
|
|
172
176
|
<Box flexDirection="column" width={width} height={height}>
|
|
173
|
-
<QueryBar width={width} search={{ ...list.search, placeholder: searchPlaceholder }} view={list.range} />
|
|
177
|
+
<QueryBar width={width} search={{ ...list.search, placeholder: searchPlaceholder }} filters={filters} view={list.range} />
|
|
174
178
|
<Box flexDirection={split ? "row" : "column"} flexGrow={1} overflow="hidden">
|
|
175
179
|
<Box flexDirection="column" width={listWidth} flexShrink={0}>
|
|
176
180
|
<Box flexDirection="column" width={listWidth} height={tableHeight} flexShrink={0} overflow="hidden">
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/** Authored placeholders only. No sample contains a provider payload or numeric value. */
|
|
2
|
+
interface SampleColumn {
|
|
3
|
+
label: string;
|
|
4
|
+
width: number;
|
|
5
|
+
/** Lower numbers stay visible first when the pane is narrow. */
|
|
6
|
+
priority: number;
|
|
7
|
+
align: "left" | "right";
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
type WallSample = { summaryHook?: string } & (
|
|
11
|
+
| { layout: "table"; columns: readonly SampleColumn[] }
|
|
12
|
+
| { layout: "prose"; issuer?: string }
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
const column = (label: string, width: number, priority: number, align: "left" | "right" = "left"): SampleColumn =>
|
|
16
|
+
({ label, width, priority, align });
|
|
17
|
+
|
|
18
|
+
const callHook = "Pro shows the transcript, Q&A and guidance";
|
|
19
|
+
|
|
20
|
+
/** Column labels/order mirror the real panes; lower-priority fields give way at narrow widths. */
|
|
21
|
+
export const WALL_TEASERS: Readonly<Record<string, WallSample>> = {
|
|
22
|
+
"risk-wall": {
|
|
23
|
+
layout: "prose", issuer: "AAPL",
|
|
24
|
+
summaryHook: "Pro shows which were added, dropped or rewritten",
|
|
25
|
+
},
|
|
26
|
+
"exec-wall": {
|
|
27
|
+
layout: "table",
|
|
28
|
+
summaryHook: "Pro shows pay for each executive",
|
|
29
|
+
columns: [column("NAME", 18, 0), column("TITLE", 16, 1), column("EQ%", 4, 3, "right"), column("TOTAL", 8, 2, "right")],
|
|
30
|
+
},
|
|
31
|
+
"ek-wall": {
|
|
32
|
+
layout: "prose", issuer: "AAPL",
|
|
33
|
+
summaryHook: "Pro shows each item and what it said",
|
|
34
|
+
},
|
|
35
|
+
"calls-wall": {
|
|
36
|
+
layout: "table", summaryHook: callHook,
|
|
37
|
+
columns: [column("TICKER", 8, 0), column("COMPANY", 12, 4), column("DATE", 10, 1), column("PERIOD", 8, 2), column("LENGTH", 7, 5, "right"), column("TONE", 11, 3)],
|
|
38
|
+
},
|
|
39
|
+
"calls-transcript-wall": { layout: "prose", issuer: "AAPL", summaryHook: callHook },
|
|
40
|
+
"diag-wall": { layout: "prose", issuer: "AAPL" },
|
|
41
|
+
"jobs-wall": {
|
|
42
|
+
layout: "table",
|
|
43
|
+
summaryHook: "Pro shows roles by function and location",
|
|
44
|
+
columns: [column("TICKER", 8, 0), column("COMPANY", 18, 5), column("OPEN", 8, 1, "right"), column("30D", 14, 4, "right"), column("POSTED 30D", 11, 3, "right"), column("NEW 7D", 8, 2, "right"), column("TOP FUNCTION", 18, 6), column("TOP COUNTRY", 12, 7)],
|
|
45
|
+
},
|
|
46
|
+
"most-wall": {
|
|
47
|
+
layout: "table",
|
|
48
|
+
columns: [column("#", 3, 10, "right"), column("TICKER", 8, 0), column("NAME", 12, 9), column("LAST", 10, 7, "right"), column("GAP%", 8, 1, "right"), column("CHG%", 8, 6, "right"), column("PRE VOL", 8, 2, "right"), column("RVOL", 6, 3, "right"), column("VWAP%", 7, 8, "right"), column("FLOAT", 7, 4, "right"), column("EVENT", 6, 5)],
|
|
49
|
+
},
|
|
50
|
+
"flow-wall": {
|
|
51
|
+
layout: "table",
|
|
52
|
+
columns: [column("TIME", 8, 1), column("TICKER", 8, 0), column("TYPE", 8, 2), column("STRIKE", 8, 4, "right"), column("EXP", 6, 5, "right"), column("SIDE", 5, 7), column("SIZE", 7, 6, "right"), column("PREM", 7, 3, "right"), column("V/OI", 6, 8, "right")],
|
|
53
|
+
},
|
|
54
|
+
"hilo-wall": {
|
|
55
|
+
layout: "table",
|
|
56
|
+
columns: [column("NEW HIGH", 10, 0), column("PRICE", 10, 1, "right"), column("COUNT", 6, 2, "right")],
|
|
57
|
+
},
|
|
58
|
+
"srch-wall": {
|
|
59
|
+
layout: "table",
|
|
60
|
+
columns: [column("TICKER", 8, 0), column("TYPE", 7, 2), column("DATE", 10, 3), column("TITLE", 14, 1), column("MATCH", 18, 4)],
|
|
61
|
+
},
|
|
62
|
+
"team": { layout: "prose" },
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/** Sign-in placements reuse the existing previews and public summary allowlist. */
|
|
66
|
+
export const SIGNIN_WALL_TEASERS: Readonly<Record<string, string>> = {
|
|
67
|
+
"risk-signin": "risk-wall",
|
|
68
|
+
"exec-signin": "exec-wall",
|
|
69
|
+
"ek-signin": "ek-wall",
|
|
70
|
+
"calls-signin": "calls-wall",
|
|
71
|
+
"calls-transcript-signin": "calls-transcript-wall",
|
|
72
|
+
"diag-signin": "diag-wall",
|
|
73
|
+
"jobs-signin": "jobs-wall",
|
|
74
|
+
"jobs-detail-signin": "jobs-wall",
|
|
75
|
+
"most-signin": "most-wall",
|
|
76
|
+
"flow-signin": "flow-wall",
|
|
77
|
+
"hilo-signin": "hilo-wall",
|
|
78
|
+
"srch-signin": "srch-wall",
|
|
79
|
+
"team-signin": "team",
|
|
80
|
+
};
|