gloomberb 0.17.6 → 0.18.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 +2 -0
- package/README.zh-CN.md +2 -0
- package/package.json +6 -1
- package/patches/electrobun@1.18.1.patch +74 -0
- package/src/account/auth-model.ts +3 -2
- package/src/account/device-signin-dialog.tsx +38 -13
- package/src/account/device-signin.ts +2 -1
- package/src/account/upgrade-dialog.tsx +6 -2
- package/src/api-client/askg.ts +5 -3
- package/src/api-client/bank-figures.ts +73 -0
- package/src/api-client/credit-boards.ts +21 -1
- package/src/api-client/crypto-markets.ts +88 -1
- package/src/api-client/data.ts +104 -4
- package/src/api-client/debt-maturities.ts +18 -0
- package/src/api-client/equity-screener.ts +3 -0
- package/src/api-client/errors.ts +13 -0
- package/src/api-client/fund-facts.ts +72 -0
- package/src/api-client/futures-curve.ts +26 -3
- package/src/api-client/geo.ts +11 -1
- package/src/api-client/index.ts +25 -2
- package/src/api-client/insider-signals.ts +95 -11
- package/src/api-client/normalizers.ts +1 -0
- package/src/api-client/paths.ts +20 -1
- package/src/api-client/request.ts +11 -3
- package/src/api-client/research-activity.ts +15 -8
- package/src/api-client/socket.ts +6 -3
- package/src/api-client/supply-chain-graph.ts +2 -2
- package/src/api-client/supply-chain.ts +8 -0
- package/src/api-client/tape.ts +12 -0
- package/src/api-client/types.ts +66 -2
- package/src/api-client/upgrade-experiment.ts +4 -3
- package/src/api-client/wall-experiments.ts +5 -3
- package/src/api-client/wall-summary.ts +3 -1
- package/src/api-client/web-experiments.ts +5 -2
- package/src/api-client/yield-curves.ts +17 -0
- package/src/app/command-bar-intro.ts +38 -0
- package/src/app/keybindings/actions.ts +1 -1
- package/src/app/pane-runtime/pane-template-runtime.ts +35 -7
- package/src/app/pane-runtime/plugin-bindings.ts +4 -0
- package/src/app/pane-runtime/ticker-open-runtime.ts +4 -14
- package/src/app/pane-runtime/ticker-open-target.ts +31 -0
- package/src/app/runtime/desktop-deeplink.ts +3 -4
- package/src/app/runtime/plugin-bindings.ts +3 -2
- package/src/app/runtime/startup.ts +3 -4
- package/src/app/runtime/ticker-refresh.ts +13 -12
- package/src/app/runtime/update.ts +3 -2
- package/src/architecture/core-builtin-allowlist.json +0 -3
- package/src/architecture/silent-catch-allowlist.json +3 -0
- package/src/architecture/ui-literals-allowlist.json +186 -0
- package/src/architecture/ui-tokens-allowlist.json +40 -0
- package/src/ask-gloom/pane-context.ts +3 -1
- package/src/brokers/signed-in/catalog.ts +2 -1
- package/src/brokers/signed-in/client.ts +7 -2
- package/src/brokers/signed-in/sign-in-dialog.tsx +120 -26
- package/src/brokers/signed-in/sign-in.ts +22 -20
- package/src/brokers/sync-broker-instance.ts +2 -1
- package/src/capabilities/chart-series.ts +2 -0
- package/src/capabilities/registry.ts +1 -3
- package/src/cli/bank-section.ts +147 -0
- package/src/cli/base-converter.ts +5 -2
- package/src/cli/board-coins.ts +70 -0
- package/src/cli/commands/fred-series.ts +90 -0
- package/src/cli/commands/market.ts +340 -69
- package/src/cli/commands/news-search.ts +35 -2
- package/src/cli/commands/options-chain.ts +7 -5
- package/src/cli/commands/options-leaps.ts +3 -3
- package/src/cli/commands/overview.ts +78 -29
- package/src/cli/commands/plugins.ts +1 -0
- package/src/cli/commands/search.ts +87 -24
- package/src/cli/commands/system.ts +5 -2
- package/src/cli/commands/ticker.ts +337 -60
- package/src/cli/context.ts +2 -1
- package/src/cli/desktop-pane-shot.ts +11 -3
- package/src/cli/earnings-calendar.ts +2 -1
- package/src/cli/errors.ts +10 -0
- package/src/cli/export-source.ts +18 -3
- package/src/cli/glossary.ts +196 -14
- package/src/cli/history-rows.ts +60 -9
- package/src/cli/index-roots.ts +26 -0
- package/src/cli/index.ts +34 -9
- package/src/cli/known-gaps.ts +156 -22
- package/src/cli/listing-arg.ts +156 -12
- package/src/cli/listing-suggestion.ts +4 -2
- package/src/cli/name-entries.ts +76 -0
- package/src/cli/not-a-ticker.ts +15 -6
- package/src/cli/pane-functions/access-gate.ts +22 -0
- package/src/cli/pane-functions/capabilities.ts +62 -4
- package/src/cli/pane-functions/catalog.ts +94 -39
- package/src/cli/pane-functions/data.ts +6 -5
- package/src/cli/pane-functions/discovery.ts +1 -1
- package/src/cli/pane-functions/dom.ts +3 -3
- package/src/cli/pane-functions/freshness.ts +49 -8
- package/src/cli/pane-functions/function-help.ts +13 -10
- package/src/cli/pane-functions/headless.ts +177 -42
- package/src/cli/pane-functions/index.ts +64 -8
- package/src/cli/pane-functions/options.ts +17 -3
- package/src/cli/pane-functions/report-notices.ts +17 -3
- package/src/cli/pane-functions/resolver.ts +48 -13
- package/src/cli/pane-functions/screenshot.ts +124 -23
- package/src/cli/pane-functions/shot-options.ts +68 -0
- package/src/cli/perpetual-contract.ts +3 -1
- package/src/cli/report-tables.ts +10 -2
- package/src/cli/staged-tickers.ts +5 -0
- package/src/cli/statement-filings.ts +261 -0
- package/src/cli/symbol-args.ts +47 -8
- package/src/cli/symbol-list.ts +9 -2
- package/src/cli/symbol-rows.ts +269 -29
- package/src/cli/ticker-resolution.ts +148 -34
- package/src/cli/treasury-yields.ts +86 -0
- package/src/cli/types.ts +3 -0
- package/src/cli/uncovered-instrument.ts +20 -0
- package/src/components/chart/composite/axis-overlays.tsx +16 -9
- package/src/components/chart/composite/composite-chart.tsx +85 -6
- package/src/components/chart/composite/downsample.ts +19 -3
- package/src/components/chart/composite/format.ts +3 -0
- package/src/components/chart/composite/legend.tsx +155 -76
- package/src/components/chart/composite/panel-bitmap.ts +8 -2
- package/src/components/chart/composite/panel-surface.tsx +3 -3
- package/src/components/chart/composite/toolbar.tsx +12 -7
- package/src/components/chart/composite/types.ts +6 -0
- package/src/components/chart/composite/use-composite-chart-keyboard.ts +28 -1
- package/src/components/chart/curve/curve-surface.tsx +1 -1
- package/src/components/chart/static/series.ts +39 -0
- package/src/components/chart/static/trail-chart-surface.tsx +2 -1
- package/src/components/command-bar/commands/collection-list.ts +45 -15
- package/src/components/command-bar/commands/collection.ts +10 -3
- package/src/components/command-bar/commands/registry.ts +2 -2
- package/src/components/command-bar/list/badge.ts +4 -3
- package/src/components/command-bar/list/model.ts +5 -0
- package/src/components/command-bar/list/view.tsx +1 -1
- package/src/components/command-bar/panel/index.tsx +19 -8
- package/src/components/command-bar/panel/native-surface.ts +6 -4
- package/src/components/command-bar/panel/prompt-example.ts +22 -0
- package/src/components/command-bar/routes/root/provider-search.ts +3 -9
- package/src/components/command-bar/routes/root/results.ts +13 -0
- package/src/components/command-bar/routes/root/start-here.ts +90 -0
- package/src/components/command-bar/routes/ticker-search/results.ts +42 -3
- package/src/components/command-bar/routes/ticker-search/route.ts +3 -10
- package/src/components/command-bar/theme-picker.tsx +3 -1
- package/src/components/command-bar/workflow/builtin.ts +5 -1
- package/src/components/command-bar/workflow/collection-actions.ts +21 -12
- package/src/components/command-bar/workflow/ops.ts +21 -1
- package/src/{plugins/builtin/portfolio-list/command-bar.ts → components/command-bar/workflow/portfolio-position.ts} +42 -9
- package/src/components/command-bar/workflow/tickers.ts +6 -4
- package/src/components/feedback-dialog.tsx +1 -1
- package/src/components/form-modal/broker-step.tsx +7 -63
- package/src/components/form-modal/content.tsx +7 -2
- package/src/components/form-modal/field-row.tsx +6 -8
- package/src/components/form-modal/host.tsx +3 -3
- package/src/components/form-modal/model.ts +3 -0
- package/src/components/form-modal/routes.ts +17 -2
- package/src/components/index.ts +6 -6
- package/src/components/input-search-bar.tsx +43 -6
- package/src/components/layout/detached-pane-shell.tsx +0 -1
- package/src/components/layout/floating-pane.tsx +0 -1
- package/src/components/layout/header.tsx +8 -7
- package/src/components/layout/pane/footer/index.tsx +7 -4
- package/src/components/layout/pane/footer/model.ts +28 -2
- package/src/components/layout/pane/header.tsx +9 -19
- package/src/components/layout/pane/index.tsx +0 -1
- package/src/components/layout/pane/instrument-coverage-gate.tsx +57 -0
- package/src/components/layout/pane/pane-tabs.tsx +4 -3
- package/src/components/layout/pane/sizing.ts +9 -0
- package/src/components/layout/pane/ticker-fate-gate.tsx +8 -2
- package/src/components/layout/shell/pane/capture.ts +44 -20
- package/src/components/layout/status-bar.tsx +3 -6
- package/src/components/markdown-text.tsx +17 -2
- package/src/components/market-board/index.tsx +19 -8
- package/src/components/metric-treemap/heat-surface.tsx +2 -7
- package/src/components/onboarding/account-step/qr-panel.tsx +5 -2
- package/src/components/onboarding/onboarding-frame.tsx +24 -21
- package/src/components/onboarding/portfolio-step/positions-panel.tsx +20 -10
- package/src/components/onboarding/wizard-positions.ts +40 -11
- package/src/components/pane-settings-dialog/desktop.tsx +12 -50
- package/src/components/pane-settings-dialog/field-dialogs.tsx +1 -1
- package/src/components/price-performance.tsx +18 -2
- package/src/components/reader/article-reader.tsx +11 -10
- package/src/components/reader/detail-reader.tsx +9 -5
- package/src/components/reader/reader-text.tsx +51 -24
- package/src/components/sign-in-code-panel.tsx +129 -75
- package/src/components/ticker/badge/index.tsx +2 -1
- package/src/components/ui/action-row.tsx +5 -2
- package/src/components/ui/audio-player.tsx +70 -0
- package/src/components/ui/card.tsx +75 -0
- package/src/components/ui/data-table/index.tsx +4 -2
- package/src/components/ui/data-table/types.ts +11 -0
- package/src/components/ui/detail-scroll-body.tsx +1 -1
- package/src/components/ui/dialog-actions.tsx +1 -21
- package/src/components/ui/display.tsx +13 -5
- package/src/components/ui/external-link.tsx +4 -2
- package/src/components/ui/fields.tsx +12 -0
- package/src/components/ui/figure.tsx +5 -3
- package/src/components/ui/frame.tsx +40 -6
- package/src/components/ui/icon.tsx +4 -0
- package/src/components/ui/index.ts +4 -1
- package/src/components/ui/list-view.tsx +8 -0
- package/src/components/ui/prose.tsx +97 -25
- package/src/components/ui/query-bar-keys.tsx +3 -1
- package/src/components/ui/query-bar.tsx +6 -0
- package/src/components/ui/quote.ts +42 -0
- package/src/components/ui/range-track.tsx +15 -2
- package/src/components/ui/reveal-in-scroll-box.ts +21 -3
- package/src/components/ui/select-button.tsx +38 -3
- package/src/components/ui/status.tsx +73 -4
- package/src/components/ui/table-layout.ts +20 -0
- package/src/components/use-pinned-moment.ts +19 -0
- package/src/core/app-runtime.ts +2 -2
- package/src/core/state/app/instrument.ts +18 -1
- package/src/core/state/app/layout.ts +6 -0
- package/src/core/state/app/state.ts +14 -2
- package/src/data/cached-query.ts +1 -1
- package/src/data/config/chart-settings.ts +3 -1
- package/src/data/config/home.ts +4 -1
- package/src/data/config/store/node.ts +9 -4
- package/src/data/config/store/normalize.ts +9 -0
- package/src/data/json-storage.ts +6 -3
- package/src/data/json-ticker-repository.ts +3 -1
- package/src/data/plugin-cache.ts +5 -1
- package/src/data/sqlite/json.ts +3 -1
- package/src/data/ticker-repository.ts +5 -2
- package/src/feedback/diagnostics.ts +2 -6
- package/src/i18n/es.ts +86 -6
- package/src/i18n/index.ts +3 -9
- package/src/i18n/ja.ts +86 -6
- package/src/i18n/ko.ts +86 -6
- package/src/i18n/zh-cn.ts +86 -6
- package/src/i18n/zh-tw.ts +86 -6
- package/src/layout-marketplace/gallery-desktop.tsx +8 -4
- package/src/market-data/bars-per-year.ts +43 -0
- package/src/market-data/bond-funds.ts +85 -0
- package/src/market-data/coordinator/auxiliary.ts +5 -2
- package/src/market-data/coordinator/index.ts +6 -5
- package/src/market-data/futures-contract.ts +102 -5
- package/src/market-data/hooks.tsx +20 -11
- package/src/market-data/market/bar-period.ts +36 -0
- package/src/market-data/market/format.ts +5 -13
- package/src/market-data/market/freshness.ts +1 -3
- package/src/market-data/market/index-level.ts +51 -0
- package/src/market-data/model-dividend-yield.ts +57 -16
- package/src/market-data/quotes/live-valuation.ts +48 -2
- package/src/market-data/realized-volatility.ts +16 -7
- package/src/market-data/tax-equivalent.ts +344 -0
- package/src/news/aggregator.ts +4 -2
- package/src/notifications/notification-log.ts +5 -3
- package/src/plugins/auto-update-node.ts +1 -0
- package/src/plugins/builtin/account-management/footer.ts +1 -1
- package/src/plugins/builtin/account-management/keyboard.ts +3 -0
- package/src/plugins/builtin/account-management/model.ts +1 -0
- package/src/plugins/builtin/account-management/pane.tsx +71 -19
- package/src/plugins/builtin/account-management/trial-cancel.ts +40 -0
- package/src/plugins/builtin/alerts/cli.ts +7 -18
- package/src/plugins/builtin/alerts/constants.ts +8 -0
- package/src/plugins/builtin/alerts/event-rows.ts +16 -0
- package/src/plugins/builtin/alerts/events-pane.tsx +2 -14
- package/src/plugins/builtin/alerts/headless.ts +182 -0
- package/src/plugins/builtin/alerts/index.tsx +3 -0
- package/src/plugins/builtin/alerts/pane.tsx +1 -7
- package/src/plugins/builtin/alerts/storage.ts +17 -1
- package/src/plugins/builtin/analytics/index.tsx +6 -1
- package/src/plugins/builtin/analytics/metrics.ts +47 -9
- package/src/plugins/builtin/analytics/risk-headless.ts +14 -2
- package/src/plugins/builtin/analytics/risk-math.ts +83 -0
- package/src/plugins/builtin/analytics/risk-model.ts +97 -4
- package/src/plugins/builtin/analytics/risk-pane.tsx +11 -6
- package/src/plugins/builtin/analytics/sector-model.ts +14 -3
- package/src/plugins/builtin/awards/headless.ts +6 -5
- package/src/plugins/builtin/awards/index.tsx +1 -1
- package/src/plugins/builtin/backtest/client.ts +38 -8
- package/src/plugins/builtin/backtest/engine.ts +25 -13
- package/src/plugins/builtin/backtest/export.ts +27 -0
- package/src/plugins/builtin/backtest/format.ts +19 -3
- package/src/plugins/builtin/backtest/headless.ts +42 -28
- package/src/plugins/builtin/backtest/index.tsx +3 -0
- package/src/plugins/builtin/backtest/pane.tsx +39 -10
- package/src/plugins/builtin/backtest/report.ts +160 -0
- package/src/plugins/builtin/backtest/rules.ts +2 -0
- package/src/plugins/builtin/backtest/window.ts +112 -0
- package/src/plugins/builtin/bond-calculator/headless.ts +3 -2
- package/src/plugins/builtin/broker-manager/add-flow.tsx +4 -4
- package/src/plugins/builtin/catalysts/headless.ts +24 -13
- package/src/plugins/builtin/catalysts/index.tsx +4 -2
- package/src/plugins/builtin/catalysts/model.ts +18 -1
- package/src/plugins/builtin/catalysts/pane.tsx +2 -2
- package/src/plugins/builtin/cds/client.ts +28 -5
- package/src/plugins/builtin/cds/headless.ts +183 -31
- package/src/plugins/builtin/cds/index.tsx +1 -1
- package/src/plugins/builtin/cds/model.ts +229 -53
- package/src/plugins/builtin/cds/pane.tsx +82 -26
- package/src/plugins/builtin/central-bank-rates/headless.ts +1 -1
- package/src/plugins/builtin/chart-composer/catalog-inventory.ts +39 -1
- package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +77 -0
- package/src/plugins/builtin/chart-composer/chart-spec.ts +15 -0
- package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +22 -2
- package/src/plugins/builtin/chart-composer/editor/desktop-view.tsx +2 -2
- package/src/plugins/builtin/chart-composer/headless-schema.ts +10 -2
- package/src/plugins/builtin/chart-composer/headless.ts +99 -21
- package/src/plugins/builtin/chart-composer/index.tsx +70 -13
- package/src/plugins/builtin/chart-composer/pane.tsx +65 -15
- package/src/plugins/builtin/chart-composer/presets.ts +79 -11
- package/src/plugins/builtin/chart-composer/series-catalog.ts +50 -14
- package/src/plugins/builtin/chart-composer/series-expression.ts +9 -7
- package/src/plugins/builtin/chart-composer/series-listings.ts +178 -0
- package/src/plugins/builtin/chart-composer/session-range.ts +87 -0
- package/src/plugins/builtin/chat/attachments/desktop.tsx +4 -1
- package/src/plugins/builtin/chat/content/composer-runtime.ts +49 -14
- package/src/plugins/builtin/chat/content/composer.tsx +22 -1
- package/src/plugins/builtin/chat/content/index.tsx +35 -5
- package/src/plugins/builtin/chat/content/layout-metrics.ts +3 -0
- package/src/plugins/builtin/chat/content/shortcuts.ts +32 -13
- package/src/plugins/builtin/chat/content/snapshot.ts +29 -6
- package/src/plugins/builtin/chat/ghost-user.ts +11 -3
- package/src/plugins/builtin/chat/layout.ts +2 -0
- package/src/plugins/builtin/chat/message/desktop.tsx +13 -5
- package/src/plugins/builtin/chat/message/header.tsx +26 -4
- package/src/plugins/builtin/chat/message/pane-chip.tsx +131 -35
- package/src/plugins/builtin/chat/message/render-state.ts +28 -1
- package/src/plugins/builtin/chat/message/terminal.tsx +9 -3
- package/src/plugins/builtin/chat/pane-links/composer.ts +87 -0
- package/src/plugins/builtin/chat/pane-links/model.ts +1 -1
- package/src/plugins/builtin/chat/share/flow.tsx +9 -73
- package/src/plugins/builtin/cloud/askg/controller.ts +5 -3
- package/src/plugins/builtin/cloud/askg/executor.ts +3 -1
- package/src/plugins/builtin/cloud/askg/lock-note.ts +16 -0
- package/src/plugins/builtin/cloud/askg/pane.tsx +6 -2
- package/src/plugins/builtin/cloud/auth-actions.tsx +4 -2
- package/src/plugins/builtin/cloud/company-picker.tsx +21 -26
- package/src/plugins/builtin/cloud/mcp-connect/dialog.tsx +5 -3
- package/src/plugins/builtin/cloud/plugin.tsx +2 -0
- package/src/plugins/builtin/cloud/team/module.tsx +5 -1
- package/src/plugins/builtin/cloud/team/pane.tsx +11 -4
- package/src/plugins/builtin/cloud/team/views.ts +11 -4
- package/src/plugins/builtin/cloud/terminal-relay/engine.ts +9 -4
- package/src/plugins/builtin/cloud/terminal-relay/prompts.tsx +3 -2
- package/src/plugins/builtin/cloud/thesis/detail.tsx +2 -1
- package/src/plugins/builtin/cloud/thesis/exposure.ts +3 -0
- package/src/plugins/builtin/cloud/thesis/prompts.tsx +3 -2
- package/src/plugins/builtin/cloud/thesis/ticker-tab.tsx +2 -1
- package/src/plugins/builtin/cloud/trial-offer-status-widget.tsx +2 -1
- package/src/plugins/builtin/cloud/verification-status-widget.tsx +2 -1
- package/src/plugins/builtin/commodities-energy/index.tsx +8 -5
- package/src/plugins/builtin/commodities-energy/view-state.ts +11 -0
- package/src/plugins/builtin/company-attention/headless.ts +15 -7
- package/src/plugins/builtin/company-attention/index.tsx +1 -1
- package/src/plugins/builtin/company-attention/model.ts +49 -4
- package/src/plugins/builtin/company-attention/pane.tsx +11 -9
- package/src/plugins/builtin/company-kpis/headless.ts +4 -3
- package/src/plugins/builtin/company-kpis/index.tsx +2 -2
- package/src/plugins/builtin/company-kpis/pane.tsx +9 -3
- package/src/plugins/builtin/congress-trades/headless.ts +23 -2
- package/src/plugins/builtin/correlation/relationship/pane.tsx +18 -46
- package/src/plugins/builtin/cot/headless.ts +5 -2
- package/src/plugins/builtin/credit-boards/cdx-pane.tsx +41 -13
- package/src/plugins/builtin/credit-boards/client.ts +9 -2
- package/src/plugins/builtin/credit-boards/headless.ts +93 -27
- package/src/plugins/builtin/credit-boards/index.tsx +15 -4
- package/src/plugins/builtin/credit-boards/model.ts +105 -6
- package/src/plugins/builtin/credit-boards/sovr-pane.tsx +14 -3
- package/src/plugins/builtin/credit-documents/detail.tsx +2 -1
- package/src/plugins/builtin/credit-documents/index.tsx +3 -0
- package/src/plugins/builtin/credit-documents/model.ts +3 -10
- package/src/plugins/builtin/crypto-board/client.ts +152 -2
- package/src/plugins/builtin/crypto-board/headless.ts +138 -19
- package/src/plugins/builtin/crypto-board/index.tsx +5 -3
- package/src/plugins/builtin/crypto-board/model.ts +210 -12
- package/src/plugins/builtin/crypto-board/pane.tsx +148 -9
- package/src/plugins/builtin/crypto-board/series.ts +52 -1
- package/src/plugins/builtin/crypto-board/supply.ts +123 -0
- package/src/plugins/builtin/debt-maturities/client.ts +54 -1
- package/src/plugins/builtin/debt-maturities/headless.ts +27 -3
- package/src/plugins/builtin/debt-maturities/index.tsx +2 -0
- package/src/plugins/builtin/debt-maturities/model.ts +58 -13
- package/src/plugins/builtin/debt-maturities/pane.tsx +47 -7
- package/src/plugins/builtin/dividend-yield/client.ts +42 -36
- package/src/plugins/builtin/dividend-yield/headless.ts +113 -18
- package/src/plugins/builtin/dividend-yield/index.tsx +5 -2
- package/src/plugins/builtin/dividend-yield/pane.tsx +37 -13
- package/src/plugins/builtin/dividend-yield/provider-client.ts +7 -3
- package/src/plugins/builtin/dividend-yield/ranking.ts +187 -0
- package/src/plugins/builtin/dividend-yield/reference-price.ts +28 -5
- package/src/plugins/builtin/dividend-yield/types.ts +6 -1
- package/src/plugins/builtin/dividend-yield/view.ts +1 -1
- package/src/plugins/builtin/docs/blocks.tsx +54 -8
- package/src/plugins/builtin/docs/pane.tsx +8 -13
- package/src/plugins/builtin/earnings/headless.ts +3 -2
- package/src/plugins/builtin/earnings-calls/data.ts +51 -0
- package/src/plugins/builtin/earnings-calls/headless.ts +7 -0
- package/src/plugins/builtin/earnings-calls/index.tsx +1 -0
- package/src/plugins/builtin/earnings-calls/model.ts +97 -0
- package/src/plugins/builtin/earnings-calls/pane.tsx +107 -7
- package/src/plugins/builtin/earnings-calls/transcript-view.tsx +140 -22
- package/src/plugins/builtin/earnings-calls/use-call-playback.ts +194 -0
- package/src/plugins/builtin/econ/calendar-model.ts +22 -0
- package/src/plugins/builtin/econ/calendar-source.ts +35 -0
- package/src/plugins/builtin/econ/index.tsx +40 -8
- package/src/plugins/builtin/econ-statistics/defs.ts +7 -0
- package/src/plugins/builtin/econ-statistics/detail.tsx +8 -1
- package/src/plugins/builtin/econ-statistics/headless.ts +26 -5
- package/src/plugins/builtin/econ-statistics/pane.tsx +4 -2
- package/src/plugins/builtin/econ-statistics/stats.ts +10 -0
- package/src/plugins/builtin/econ-statistics/view.ts +19 -0
- package/src/plugins/builtin/equity-screener/client.ts +1 -1
- package/src/plugins/builtin/equity-screener/model.ts +46 -4
- package/src/plugins/builtin/equity-screener/pane.tsx +3 -0
- package/src/plugins/builtin/estimate-revisions/client.ts +32 -22
- package/src/plugins/builtin/estimate-revisions/headless.ts +1 -0
- package/src/plugins/builtin/estimate-revisions/index.tsx +1 -0
- package/src/plugins/builtin/estimate-revisions/pane.tsx +5 -3
- package/src/plugins/builtin/executives/index.tsx +1 -0
- package/src/plugins/builtin/exposure/editor.tsx +3 -3
- package/src/plugins/builtin/fear-greed/index.tsx +9 -0
- package/src/plugins/builtin/filing-events/index.tsx +1 -0
- package/src/plugins/builtin/futures/index.tsx +2 -2
- package/src/plugins/builtin/futures/model.ts +34 -21
- package/src/plugins/builtin/futures/table.tsx +1 -1
- package/src/plugins/builtin/futures/use-board-terms.ts +2 -2
- package/src/plugins/builtin/futures-curve/headless.ts +4 -2
- package/src/plugins/builtin/futures-curve/model.ts +5 -7
- package/src/plugins/builtin/help/index.tsx +55 -8
- package/src/plugins/builtin/help/shortcut-table.tsx +15 -2
- package/src/plugins/builtin/holders/headless.ts +12 -0
- package/src/plugins/builtin/insider/headless.ts +311 -41
- package/src/plugins/builtin/insider/index.tsx +280 -106
- package/src/plugins/builtin/insider/insiders.tsx +224 -0
- package/src/plugins/builtin/insider/signals-cells.tsx +52 -0
- package/src/plugins/builtin/insider/signals-client.ts +135 -11
- package/src/plugins/builtin/insider/signals-model.ts +628 -56
- package/src/plugins/builtin/insider/signals.tsx +283 -83
- package/src/plugins/builtin/ipo-calendar/headless.ts +17 -7
- package/src/plugins/builtin/ipo-calendar/index.tsx +23 -3
- package/src/plugins/builtin/ipo-calendar/model.ts +84 -36
- package/src/plugins/builtin/ipo-calendar/pane.tsx +20 -8
- package/src/plugins/builtin/iv-history/headless.ts +2 -0
- package/src/plugins/builtin/jobs/headless.ts +1 -0
- package/src/plugins/builtin/jobs/index.tsx +1 -0
- package/src/plugins/builtin/jodi/headless.ts +2 -0
- package/src/plugins/builtin/kelly-sizer/pane.tsx +1 -1
- package/src/plugins/builtin/kelly-sizer/portfolio.ts +1 -1
- package/src/plugins/builtin/market-heatmap/headless.ts +1 -0
- package/src/plugins/builtin/market-heatmap/portfolio.ts +3 -1
- package/src/plugins/builtin/market-valuation/pane.tsx +1 -1
- package/src/plugins/builtin/market-valuation/zone-scale/desktop.tsx +31 -57
- package/src/plugins/builtin/mna/distress/headless.ts +2 -1
- package/src/plugins/builtin/mna/headless.ts +14 -2
- package/src/plugins/builtin/mna/index.tsx +1 -0
- package/src/plugins/builtin/news/headless.ts +4 -0
- package/src/plugins/builtin/news/wire/news/footer.ts +5 -3
- package/src/plugins/builtin/news/wire/news/table.tsx +57 -11
- package/src/plugins/builtin/notes/cli.ts +8 -4
- package/src/plugins/builtin/notes/files.ts +66 -20
- package/src/plugins/builtin/notes/migration.ts +18 -6
- package/src/plugins/builtin/notes/owner.tsx +3 -2
- package/src/plugins/builtin/notes/quick-notes-pane.tsx +3 -2
- package/src/plugins/builtin/options-scenario/client.ts +7 -4
- package/src/plugins/builtin/options-scenario/headless.ts +5 -3
- package/src/plugins/builtin/pe-band/index.tsx +1 -1
- package/src/plugins/builtin/pe-band/model.ts +1 -15
- package/src/plugins/builtin/perps/headless.ts +30 -13
- package/src/plugins/builtin/perps/model.ts +45 -3
- package/src/plugins/builtin/perps/pane.tsx +7 -7
- package/src/plugins/builtin/portfolio-list/cell-version.ts +10 -4
- package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +128 -14
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +108 -46
- package/src/plugins/builtin/portfolio-list/cli/render.ts +368 -45
- package/src/plugins/builtin/portfolio-list/cli/shared.ts +8 -2
- package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +24 -34
- package/src/plugins/builtin/portfolio-list/grid.tsx +3 -1
- package/src/plugins/builtin/portfolio-list/headless.ts +151 -29
- package/src/plugins/builtin/portfolio-list/income.ts +296 -0
- package/src/plugins/builtin/portfolio-list/metrics.ts +2 -2
- package/src/plugins/builtin/portfolio-list/pane/futures-terms.ts +58 -0
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +27 -10
- package/src/plugins/builtin/portfolio-list/pane/supplemental.ts +47 -28
- package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +3 -2
- package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +10 -3
- package/src/plugins/builtin/portfolio-list/summary/index.tsx +26 -4
- package/src/plugins/builtin/portfolio-list/summary/totals.ts +31 -3
- package/src/plugins/builtin/portfolio-list/table.tsx +25 -5
- package/src/plugins/builtin/power/prices-headless.ts +2 -1
- package/src/plugins/builtin/realized-vol/chart-model.ts +29 -5
- package/src/plugins/builtin/realized-vol/charts.tsx +14 -8
- package/src/plugins/builtin/realized-vol/evidence.ts +2 -0
- package/src/plugins/builtin/realized-vol/headless.ts +6 -4
- package/src/plugins/builtin/realized-vol/model.ts +5 -1
- package/src/plugins/builtin/realized-vol/pane.tsx +31 -11
- package/src/plugins/builtin/realized-vol/settings.ts +1 -1
- package/src/plugins/builtin/research/analyst-headless.ts +4 -0
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +2 -0
- package/src/plugins/builtin/research/event-model.ts +22 -2
- package/src/plugins/builtin/research/headless-schema.ts +1 -0
- package/src/plugins/builtin/research/headless.ts +3 -0
- package/src/plugins/builtin/research/index.tsx +3 -0
- package/src/plugins/builtin/research/relative-valuation-columns.ts +27 -5
- package/src/plugins/builtin/research/relative-valuation-headless.ts +2 -0
- package/src/plugins/builtin/revenue-breakdown/index.tsx +1 -0
- package/src/plugins/builtin/reverse-dcf/headless.ts +9 -6
- package/src/plugins/builtin/reverse-dcf/index.tsx +2 -2
- package/src/plugins/builtin/reverse-dcf/model.ts +51 -4
- package/src/plugins/builtin/reverse-dcf/pane.tsx +23 -10
- package/src/plugins/builtin/risk-factors/headless.ts +7 -0
- package/src/plugins/builtin/risk-factors/index.tsx +1 -0
- package/src/plugins/builtin/scanner/feed.ts +5 -3
- package/src/plugins/builtin/scanner/headless.ts +9 -57
- package/src/plugins/builtin/scanner/index.ts +1 -2
- package/src/plugins/builtin/sec/forms.ts +2 -6
- package/src/plugins/builtin/sec/fund-facts-view.tsx +53 -0
- package/src/plugins/builtin/sec/fund-facts.ts +328 -0
- package/src/plugins/builtin/sec/headless.ts +140 -44
- package/src/plugins/builtin/sec/index.tsx +95 -30
- package/src/plugins/builtin/sec/model.ts +2 -44
- package/src/plugins/builtin/shared/headless-options.ts +10 -0
- package/src/plugins/builtin/shared/locked-rows.tsx +3 -1
- package/src/plugins/builtin/shared/move-rank.ts +108 -0
- package/src/plugins/builtin/shared/report-freshness.ts +25 -9
- package/src/plugins/builtin/shared/scanner-capture.ts +95 -0
- package/src/plugins/builtin/shared/treasury-cutoffs.ts +15 -0
- package/src/plugins/builtin/shared/use-quote-board.ts +1 -0
- package/src/plugins/builtin/shared/volatility/live-session.ts +34 -0
- package/src/plugins/builtin/shared/volatility-indices.ts +32 -0
- package/src/plugins/builtin/short-interest/headless.ts +3 -0
- package/src/plugins/builtin/short-interest/watch-model.ts +2 -2
- package/src/plugins/builtin/social-mentions/client.ts +8 -1
- package/src/plugins/builtin/social-mentions/pane.tsx +8 -6
- package/src/plugins/builtin/supply-chain/client.ts +12 -3
- package/src/plugins/builtin/supply-chain/disclosure-quote.tsx +9 -5
- package/src/plugins/builtin/supply-chain/evidence.ts +3 -1
- package/src/plugins/builtin/supply-chain/flow-layout.ts +2 -1
- package/src/plugins/builtin/supply-chain/flow.tsx +23 -16
- package/src/plugins/builtin/supply-chain/graph-client.ts +8 -5
- package/src/plugins/builtin/supply-chain/graph-evidence.ts +1 -1
- package/src/plugins/builtin/supply-chain/graph-model.ts +10 -2
- package/src/plugins/builtin/supply-chain/graph-pane.tsx +9 -7
- package/src/plugins/builtin/supply-chain/graph.tsx +8 -6
- package/src/plugins/builtin/supply-chain/headless.ts +69 -27
- package/src/plugins/builtin/supply-chain/index.tsx +1 -1
- package/src/plugins/builtin/supply-chain/model.ts +76 -15
- package/src/plugins/builtin/supply-chain/pane.tsx +29 -15
- package/src/plugins/builtin/supply-chain/row-evidence.tsx +5 -4
- package/src/plugins/builtin/themes/model.ts +2 -5
- package/src/plugins/builtin/thirteenf/api.ts +50 -2
- package/src/plugins/builtin/thirteenf/data.ts +250 -11
- package/src/plugins/builtin/thirteenf/headless.ts +311 -28
- package/src/plugins/builtin/thirteenf/index.tsx +4 -1
- package/src/plugins/builtin/thirteenf/model.ts +244 -19
- package/src/plugins/builtin/thirteenf/overlap-pane.tsx +133 -33
- package/src/plugins/builtin/thirteenf/overlap.ts +1 -1
- package/src/plugins/builtin/thirteenf/pane.tsx +24 -5
- package/src/plugins/builtin/thirteenf/report-notes.ts +78 -0
- package/src/plugins/builtin/thirteenf/types.ts +49 -0
- package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +22 -8
- package/src/plugins/builtin/ticker-detail/data-panes/history-bars.ts +17 -1
- package/src/plugins/builtin/ticker-detail/financials/model.ts +2 -42
- package/src/plugins/builtin/ticker-detail/financials/tab.tsx +1 -1
- package/src/plugins/builtin/ticker-detail/headless.ts +23 -10
- package/src/plugins/builtin/ticker-detail/overview/components.tsx +27 -3
- package/src/plugins/builtin/ticker-detail/overview/dividend.ts +60 -0
- package/src/plugins/builtin/ticker-detail/overview/model.ts +46 -9
- package/src/plugins/builtin/ticker-detail/overview/pane.tsx +3 -0
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +36 -3
- package/src/plugins/builtin/ticker-detail/quote-monitor/card.tsx +18 -19
- package/src/plugins/builtin/time-sales/client.ts +7 -4
- package/src/plugins/builtin/time-sales/headless.ts +71 -22
- package/src/plugins/builtin/time-sales/model.ts +12 -0
- package/src/plugins/builtin/time-sales/pane.tsx +31 -7
- package/src/plugins/builtin/time-sales/window.ts +128 -0
- package/src/plugins/builtin/trace-bonds/client.ts +351 -33
- package/src/plugins/builtin/trace-bonds/headless.ts +60 -22
- package/src/plugins/builtin/trace-bonds/index.tsx +4 -2
- package/src/plugins/builtin/trace-bonds/model.ts +27 -25
- package/src/plugins/builtin/trace-bonds/pane.tsx +63 -45
- package/src/plugins/builtin/treasury-auctions/cache.ts +61 -15
- package/src/plugins/builtin/treasury-auctions/client.ts +45 -10
- package/src/plugins/builtin/treasury-auctions/headless.ts +35 -13
- package/src/plugins/builtin/treasury-auctions/index.tsx +5 -2
- package/src/plugins/builtin/treasury-auctions/model.ts +20 -16
- package/src/plugins/builtin/treasury-auctions/pane.tsx +29 -12
- package/src/plugins/builtin/vol-surface/charts.tsx +2 -1
- package/src/plugins/builtin/vol-surface/headless.ts +3 -2
- package/src/plugins/builtin/vol-surface/pane.tsx +2 -1
- package/src/plugins/builtin/vol-surface/stored.ts +4 -7
- package/src/plugins/builtin/volatility/chart-model.ts +16 -15
- package/src/plugins/builtin/volatility/charts.tsx +5 -5
- package/src/plugins/builtin/volatility/client.ts +73 -2
- package/src/plugins/builtin/volatility/evidence.ts +13 -14
- package/src/plugins/builtin/volatility/headless.ts +13 -7
- package/src/plugins/builtin/volatility/index.tsx +1 -1
- package/src/plugins/builtin/volatility/model.ts +104 -38
- package/src/plugins/builtin/volatility/pane.tsx +42 -24
- package/src/plugins/builtin/volatility/series.ts +22 -13
- package/src/plugins/builtin/world-venue-map/geo-series.ts +9 -0
- package/src/plugins/builtin/world-venue-map/headless.ts +8 -5
- package/src/plugins/builtin/world-venue-map/index.ts +16 -2
- package/src/plugins/builtin/world-venue-map/map.tsx +13 -17
- package/src/plugins/builtin/yield-curve/curves.ts +29 -5
- package/src/plugins/builtin/yield-curve/headless.ts +41 -8
- package/src/plugins/builtin/yield-curve/history.ts +5 -5
- package/src/plugins/builtin/yield-curve/index.tsx +30 -13
- package/src/plugins/compat.ts +3 -1
- package/src/plugins/dependencies.ts +8 -2
- package/src/plugins/host-link.ts +12 -5
- package/src/plugins/installer.ts +16 -7
- package/src/plugins/loader.ts +9 -2
- package/src/plugins/marketplace/activation.ts +10 -4
- package/src/plugins/registry/host-actions.ts +3 -0
- package/src/plugins/registry/index.ts +3 -1
- package/src/{plugins/builtin/portfolio-list → portfolio}/allocation.ts +74 -12
- package/src/{plugins/builtin/portfolio-list → portfolio}/column-values.ts +140 -53
- package/src/portfolio/futures-positions.ts +213 -0
- package/src/portfolio/futures-terms.ts +75 -0
- package/src/portfolio/manual-lots.ts +78 -0
- package/src/portfolio/mutations.ts +54 -10
- package/src/portfolio/position-metrics.ts +44 -10
- package/src/portfolio/valuation-basis.ts +31 -4
- package/src/public/__snapshots__/public-api.test.ts.snap +4 -0
- package/src/public/time-series.ts +2 -1
- package/src/remote/confirm-change.tsx +2 -1
- package/src/remote/server.ts +1 -1
- package/src/remote/watchlist.ts +9 -1
- package/src/renderers/dom/data-table/row.tsx +1 -1
- package/src/renderers/dom/desktop/audio-player.tsx +312 -0
- package/src/renderers/dom/desktop/control-styles.ts +17 -82
- package/src/renderers/dom/desktop/controls.tsx +39 -63
- package/src/renderers/dom/desktop/dialog-actions.tsx +13 -53
- package/src/renderers/dom/desktop/icons.tsx +8 -0
- package/src/renderers/dom/desktop/list-view.tsx +6 -6
- package/src/renderers/dom/desktop/popover.tsx +0 -3
- package/src/renderers/dom/desktop/query-bar.tsx +6 -4
- package/src/renderers/dom/desktop/select-field.tsx +9 -8
- package/src/renderers/dom/desktop/stack-header.ts +3 -0
- package/src/renderers/dom/dom-ui-host.tsx +3 -2
- package/src/renderers/dom/host/chart-surface.tsx +3 -3
- package/src/renderers/dom/host/size-observer.ts +33 -4
- package/src/renderers/dom/host/surface-3d.tsx +3 -2
- package/src/renderers/dom/host/surface-fit.ts +4 -1
- package/src/renderers/dom/host/tabs.tsx +22 -132
- package/src/renderers/dom/styles.css +358 -160
- package/src/renderers/electrobun/bun/core-capabilities.ts +1 -1
- package/src/renderers/electrobun/bun/desktop/backend.ts +1 -1
- package/src/renderers/electrobun/bun/desktop/initialization.ts +1 -0
- package/src/renderers/electrobun/bun/desktop/state-broadcaster.ts +43 -1
- package/src/renderers/electrobun/bun/desktop/workspace/requests.ts +5 -1
- package/src/renderers/electrobun/shared/rpc-codec.ts +7 -0
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +21 -17
- package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +3 -3
- package/src/renderers/electrobun/view/desktop/window/bridge.ts +6 -8
- package/src/renderers/electrobun/view/desktop/window/snapshot.ts +18 -0
- package/src/series/capability.ts +1 -0
- package/src/series/files.ts +9 -3
- package/src/series/registry.ts +40 -14
- package/src/series/resolve.ts +121 -18
- package/src/series/standalone.ts +3 -2
- package/src/series/types.ts +55 -1
- package/src/series/validate.ts +39 -0
- package/src/shares/api.ts +26 -7
- package/src/shares/bug-report-dialog.tsx +2 -2
- package/src/shares/bug-report-flow.tsx +4 -7
- package/src/shares/capture-flow.ts +5 -4
- package/src/shares/capture-preview.tsx +2 -2
- package/src/shares/chat.ts +7 -27
- package/src/shares/flow.tsx +86 -40
- package/src/shares/location.ts +1 -3
- package/src/shares/pane-image.ts +11 -9
- package/src/shares/pane.ts +5 -2
- package/src/shares/payload.ts +1 -1
- package/src/shares/personal-pane.ts +3 -3
- package/src/shares/portable-layout.ts +9 -2
- package/src/shares/ready.ts +42 -0
- package/src/shares/test-harness.ts +62 -0
- package/src/sources/gloomberb-cloud/batched-lookups.ts +73 -0
- package/src/sources/gloomberb-cloud/index.ts +64 -12
- package/src/sources/gloomberb-cloud/normalizers.ts +31 -2
- package/src/sources/gloomberb-cloud/perpetuals.ts +20 -1
- package/src/sources/history-omitted.ts +34 -0
- package/src/sources/history-result.ts +3 -0
- package/src/sources/history-retention.ts +1 -1
- package/src/sources/provider-errors.ts +43 -1
- package/src/sources/provider-router/batches.ts +3 -2
- package/src/sources/provider-router/cache.ts +2 -1
- package/src/sources/provider-router/cached-routes.ts +9 -3
- package/src/sources/provider-router/history.ts +9 -8
- package/src/sources/provider-router/index.ts +18 -3
- package/src/sources/provider-router/primary.ts +5 -4
- package/src/sources/provider-router/quote-route.ts +3 -1
- package/src/sources/provider-router/routing.ts +2 -1
- package/src/sources/provider-router/search.ts +47 -13
- package/src/sources/provider-router/streaming.ts +7 -4
- package/src/sources/sec-edgar.ts +1 -3
- package/src/state/app/context/index.tsx +9 -13
- package/src/state/app/tab-cursor.ts +149 -12
- package/src/state/hooks/quote-streaming.ts +3 -2
- package/src/state/hooks/session-snapshot.ts +3 -2
- package/src/state/persist-scheduler.ts +12 -4
- package/src/sync/controller.ts +22 -1
- package/src/sync/core-contributors.ts +58 -15
- package/src/team/collections-sync.ts +14 -4
- package/src/team/collections.ts +40 -11
- package/src/team/store.ts +5 -4
- package/src/telemetry/attention-counts.ts +8 -2
- package/src/telemetry/crash-reports-dom.ts +3 -0
- package/src/telemetry/crash-reports-node.ts +7 -4
- package/src/telemetry/crash-reports.ts +11 -11
- package/src/telemetry/usage-counts.ts +16 -12
- package/src/theme/colors.ts +2 -0
- package/src/theme/font-scale.ts +2 -0
- package/src/theme/ui-tokens.ts +71 -0
- package/src/tickers/batched-lookups.ts +186 -0
- package/src/tickers/company-name-listing.ts +97 -0
- package/src/tickers/company-name.ts +13 -0
- package/src/tickers/instrument-coverage.ts +112 -0
- package/src/tickers/listing-fate.ts +49 -9
- package/src/tickers/listing-venues.ts +24 -5
- package/src/tickers/open-target.ts +13 -5
- package/src/tickers/search/index.ts +112 -35
- package/src/tickers/search/ranking.ts +49 -1
- package/src/tickers/terminal-codes.ts +79 -0
- package/src/tickers/ticker-changes.ts +74 -3
- package/src/tickers/us-listing.ts +2 -1
- package/src/time-series/chart-data.ts +79 -8
- package/src/time-series/fundamentals.ts +55 -7
- package/src/time-series/ice-credit.ts +17 -2
- package/src/time-series/live-bars.ts +21 -8
- package/src/time-series/live-quotes.ts +2 -3
- package/src/time-series/price-comparison.ts +6 -1
- package/src/time-series/resolve.ts +65 -10
- package/src/time-series/spec.ts +2 -1
- package/src/time-series/studies.ts +3 -3
- package/src/time-series/types.ts +22 -0
- package/src/time-series/use-chart-resolution.ts +2 -1
- package/src/types/config.ts +7 -0
- package/src/types/data-provider.ts +20 -0
- package/src/types/headless.ts +142 -1
- package/src/types/instrument.ts +6 -0
- package/src/types/plugin.ts +32 -9
- package/src/types/price-history.ts +5 -0
- package/src/types/ticker-changes.ts +19 -0
- package/src/types/ticker.ts +10 -2
- package/src/ui/context-menu.tsx +2 -0
- package/src/ui/host.tsx +40 -4
- package/src/ui/measured-cells.ts +13 -7
- package/src/ui/qr.ts +7 -5
- package/src/updater/index.ts +5 -5
- package/src/utils/calendar-date.ts +86 -27
- package/src/utils/currency-units.ts +17 -0
- package/src/utils/debug-log.ts +1 -1
- package/src/utils/dividend-cash.ts +48 -0
- package/src/utils/dom-screenshot-rasters.ts +3 -1
- package/src/utils/dom-screenshot.ts +14 -10
- package/src/utils/exchange-rate-snapshot.ts +9 -4
- package/src/utils/external-url.ts +1 -0
- package/src/utils/fiscal-period.ts +47 -0
- package/src/utils/format.ts +5 -2
- package/src/utils/forward-dividend.ts +160 -11
- package/src/utils/futures-generic.ts +34 -8
- package/src/utils/http-proxy-response.ts +2 -1
- package/src/utils/local-utc-offset.ts +2 -0
- package/src/utils/log-failure.ts +31 -0
- package/src/utils/option-expiry.ts +12 -12
- package/src/utils/price-history-integrity.ts +56 -0
- package/src/utils/price-history.ts +13 -1
- package/src/utils/sec-filings.ts +245 -0
- package/src/utils/selection-clipboard.ts +5 -2
- package/src/utils/throttled-fetch.ts +1 -0
- package/src/{plugins/builtin/dividend-yield/trailing-cash.ts → utils/trailing-dividend.ts} +55 -8
- package/src/utils/url.ts +1 -0
- package/src/utils/utc-time.ts +11 -0
- package/src/plugins/builtin/chat/share/targets.ts +0 -27
- package/src/renderers/dom/host/top-surface.ts +0 -119
- package/src/shares/dialog.tsx +0 -221
- package/src/shares/live.ts +0 -19
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import type { SupplyRow } from "../../../api-client/supply-chain";
|
|
2
|
-
import
|
|
3
|
-
import type {
|
|
2
|
+
import { DATE_OPTION_EXAMPLES, isoDateOption } from "../../../utils/calendar-date";
|
|
3
|
+
import type { GraphEvidence, GraphPath, GraphPayload } from "../../../api-client/supply-chain-graph";
|
|
4
|
+
import type { HeadlessBundleResult, HeadlessBundleSection, HeadlessPaneColumn, HeadlessPaneDefinition, HeadlessPaneRow } from "../../../types/plugin";
|
|
4
5
|
import { fetchSupplyChain } from "./client";
|
|
5
6
|
import { evidenceDate, evidenceLabel, isUnconfirmed, matchesSupplyOptions, supplyOptions, trustTier } from "./trust";
|
|
6
7
|
import { fetchSupplyGraph, graphOptions } from "./graph-client";
|
|
7
|
-
import { exposureLabel, pathLabel } from "./graph-model";
|
|
8
|
-
import {
|
|
8
|
+
import { entityTicker, exposureLabel, pathLabel } from "./graph-model";
|
|
9
|
+
import { graphEvidenceRow } from "./graph-evidence";
|
|
10
|
+
import { counterpartyName, disclosedValue, disclosureText, earlierRows, isTaggedFact, lockedDisclosures, nativeValue, periodText, roleLabel, shareParts, supplyPreviewNote, supplyRoleCounts } from "./model";
|
|
9
11
|
|
|
10
12
|
/**
|
|
11
13
|
* The Table tab's columns, printed as the pane prints them: the share with
|
|
@@ -20,6 +22,7 @@ function tableColumns(rows: HeadlessPaneRow[], sources: ReadonlyMap<HeadlessPane
|
|
|
20
22
|
return (source ? read(source) : value == null ? null : String(value)) ?? "-";
|
|
21
23
|
};
|
|
22
24
|
const valued = rows.some((row) => { const source = sources.get(row); return !!source && (nativeValue(source) !== null || source.usd !== null); });
|
|
25
|
+
const lengths = rows.some((row) => sources.get(row)?.periodMonths != null);
|
|
23
26
|
return [
|
|
24
27
|
{ key: "counterparty", header: "Counterparty", format: cell(counterpartyName) },
|
|
25
28
|
{ key: "evidenceTier", header: "Evidence" },
|
|
@@ -30,7 +33,9 @@ function tableColumns(rows: HeadlessPaneRow[], sources: ReadonlyMap<HeadlessPane
|
|
|
30
33
|
textFormat: cell((row) => { const share = shareParts(row, focusId); return share ? `${share.value} ${share.basis}` : null; }) },
|
|
31
34
|
...(valued ? [{ key: "usd", header: "Value", align: "right" as const,
|
|
32
35
|
format: cell((row) => nativeValue(row) === null && row.usd === null ? null : disclosedValue(row).replace(/ (disclosed|derived)$/, "")) }] : []),
|
|
33
|
-
|
|
36
|
+
// Exports keep the end date; the text adds the period's length when the source states it.
|
|
37
|
+
// A narrow table may cut the length as it cuts other text, never the date (eleven cells: the date and an ellipsis).
|
|
38
|
+
{ key: "period", header: "Period", textFormat: cell(periodText), ...(lengths ? { minWidth: 11 } : {}) },
|
|
34
39
|
{ key: "filed", header: "Published", format: cell(evidenceDate) },
|
|
35
40
|
];
|
|
36
41
|
}
|
|
@@ -40,6 +45,18 @@ const pathColumns = [
|
|
|
40
45
|
{ key: "score", header: "Rank score", description: "Product of normalized edge weights; not a probability." },
|
|
41
46
|
{ key: "confidence", header: "Confidence" }, { key: "exposureLabel", header: "Estimated exposure" },
|
|
42
47
|
];
|
|
48
|
+
/**
|
|
49
|
+
* What a graph disclosure says in words: the text itself, or for a tagged
|
|
50
|
+
* XBRL fact the sentence a filing-text disclosure of the same link quotes,
|
|
51
|
+
* else the fact read out ("Customer, Gold, revenue").
|
|
52
|
+
*/
|
|
53
|
+
function graphStatement(item: GraphEvidence, siblings: readonly GraphEvidence[]): string {
|
|
54
|
+
const row = graphEvidenceRow(item);
|
|
55
|
+
if (!isTaggedFact(row)) return item.quote;
|
|
56
|
+
const sentence = siblings.find((other) => other.id !== item.id && other.sourceKind === "filing_text" && other.reporter.id === item.reporter.id && other.quote.trim());
|
|
57
|
+
return sentence?.quote ?? disclosureText(row);
|
|
58
|
+
}
|
|
59
|
+
|
|
43
60
|
function graphReport(data: GraphPayload, target: string): HeadlessBundleResult {
|
|
44
61
|
const links = new Map(data.links.map(link => [link.id, link]));
|
|
45
62
|
const nodes = new Map(data.nodes.map(node => [node.id, node]));
|
|
@@ -54,17 +71,20 @@ function graphReport(data: GraphPayload, target: string): HeadlessBundleResult {
|
|
|
54
71
|
title: direction === "upstream" ? "Upstream suppliers" : direction === "downstream" ? "Downstream customers" : "Related companies",
|
|
55
72
|
columns: [{ key: "company", header: "Company" }, { key: "ticker", header: "Ticker" }, ...pathColumns],
|
|
56
73
|
rows: data[direction].map(reach => ({ ...route(data.options.ranking === "shortest" ? reach.shortestPath : reach.bestPath), entityId: reach.entityId, company: nodes.get(reach.entityId)?.name,
|
|
57
|
-
ticker: nodes.get(reach.entityId)
|
|
74
|
+
ticker: nodes.get(reach.entityId) ? entityTicker(nodes.get(reach.entityId)!) : null, direction: reach.direction, bestPath: route(reach.bestPath), shortestPath: route(reach.shortestPath) })),
|
|
58
75
|
}));
|
|
59
76
|
sections.push({ title: "Disclosure evidence", columns: [
|
|
60
77
|
{ key: "reporter", header: "Reporting company" }, { key: "from", header: "Supplier / from" }, { key: "to", header: "Customer / to" },
|
|
61
78
|
{ key: "role", header: "Role" }, { key: "pct", header: "% disclosed" }, { key: "denominator", header: "Denominator" },
|
|
62
|
-
{ key: "period", header: "Period"
|
|
63
|
-
{ key: "
|
|
79
|
+
{ key: "period", header: "Period", textFormat: (value, row) => periodText({ period: String(value), periodMonths: row.periodMonths as number | null }) },
|
|
80
|
+
{ key: "filed", header: "Filed" }, { key: "confidence", header: "Confidence" },
|
|
81
|
+
// A tagged XBRL fact prints the link's filing sentence when one names the same pair, otherwise the fact in words; exports keep the stored text.
|
|
82
|
+
{ key: "quote", header: "Quote", textFormat: (value, row) => row.statement == null ? String(value ?? "") : String(row.statement) }, { key: "filingUrl", header: "Filing" },
|
|
64
83
|
], rows: data.links.flatMap(link => link.evidence.map(item => ({ id: item.id, linkId: link.id, primary: item.id === link.primaryEvidenceId,
|
|
84
|
+
statement: graphStatement(item, link.evidence),
|
|
65
85
|
reporter: item.reporter.name, from: item.from.name, to: item.to.name, role: item.role, pct: item.pctOfRevenue ?? null,
|
|
66
86
|
denominator: item.pctBasis && !(item.sourceKind === "xbrl" && item.pctScope) ? `${item.reporter.name} ${item.pctBasis}${item.pctScope ? ` (${item.pctScope})` : ""}` : null,
|
|
67
|
-
pctBasis: item.pctBasis, pctScope: item.pctScope, period: item.period, filed: item.filedDate, asOf: item.asOf,
|
|
87
|
+
pctBasis: item.pctBasis, pctScope: item.pctScope, period: item.period, periodMonths: item.periodMonths ?? null, filed: item.filedDate, asOf: item.asOf,
|
|
68
88
|
confidence: item.confidence, quote: item.quote, quoteLanguage: item.quoteLanguage, quoteGloss: item.quoteGloss ?? null,
|
|
69
89
|
quoteGlossKind: item.quoteGloss ? "machine_translation" : null, nativeAmount: item.nativeAmount ?? null,
|
|
70
90
|
nativeCurrency: item.nativeCurrency ?? null, nativeScale: item.nativeScale ?? null, jurisdiction: item.jurisdiction,
|
|
@@ -93,7 +113,8 @@ export const supplyChainHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
|
93
113
|
"Unconfirmed leads are opt-in and excluded from flow and disclosed values.", "Restricted publisher articles expose links only.",
|
|
94
114
|
"Table and Flow evidence tiers differ from Graph and Path evidence tiers."] },
|
|
95
115
|
options: [
|
|
96
|
-
|
|
116
|
+
// No default: left out, the report prints both views; the pane opens on what the company says.
|
|
117
|
+
{ key: "view", type: "enum", settingKey: "view", values: [{ value: "says" }, { value: "names" }], description: "Statements by the company, or other sources naming it; both when left out." },
|
|
97
118
|
{ key: "tab", type: "enum", settingKey: "tab", defaultValue: "table", values: ["table", "flow", "graph", "path"].map(value => ({ value })), description: "Disclosures table, direct flow, multi-hop graph or routes to a target." },
|
|
98
119
|
{ key: "route", type: "integer", minimum: 1, maximum: 50, defaultValue: 1, settingKey: "route", description: "Selected route for graph and evidence screenshots." },
|
|
99
120
|
{ key: "evidence", type: "boolean", settingKey: "evidence", defaultValue: false, description: "Open selected relationship or path evidence in screenshots." },
|
|
@@ -106,7 +127,7 @@ export const supplyChainHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
|
106
127
|
{ key: "min-confidence", type: "string", settingKey: "minConfidence", defaultValue: "0", description: "Minimum edge confidence, 0 to 1." },
|
|
107
128
|
{ key: "limit", type: "integer", settingKey: "limit", minimum: 1, maximum: 50, defaultValue: 50, description: "Maximum results per graph section or paths." },
|
|
108
129
|
{ key: "ranking", type: "enum", settingKey: "ranking", defaultValue: "score", values: [{ value: "score" }, { value: "shortest" }], description: "Rank paths by edge-weight product or fewest hops." },
|
|
109
|
-
{ key: "as-of", type: "string", settingKey: "asOf", description:
|
|
130
|
+
{ key: "as-of", type: "string", settingKey: "asOf", placeholder: "date", description: `Include disclosures known by this date, as ${DATE_OPTION_EXAMPLES}.`, normalize: (value) => isoDateOption(value, "as-of") },
|
|
110
131
|
{ key: "to", type: "string", settingKey: "to", description: "Target company ticker or id:<entity-id>; required for Path." },
|
|
111
132
|
],
|
|
112
133
|
describe: (args) => `Supply chain | ${args.symbols[0]}${args.options.to ? ` → ${args.options.to}` : ""}`,
|
|
@@ -123,21 +144,42 @@ export const supplyChainHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
|
123
144
|
// The pane's figures, per tab: Table shows one direction, Flow both.
|
|
124
145
|
const figures = (key: "counterparties" | "locked") => Object.fromEntries(([["says", ["says"]], ["names", ["names"]], ["flow", ["says", "names"]]] as const)
|
|
125
146
|
.map(([scope, views]) => [scope, Object.fromEntries(supplyRoleCounts(data, views, options).filter((entry) => entry[key] > 0).map((entry) => [entry.role, entry[key]]))]));
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
147
|
+
const record = (row: SupplyRow) => sourced(row, { counterparty: row.counterparty.name, ticker: entityTicker(row.counterparty), aggregate: row.counterparty.aggregate, role: row.role, direction: row.direction,
|
|
148
|
+
pct: row.pctOfRevenue, pctBasis: row.pctBasis, pctScope: row.pctScope, usd: row.usd, usdBasis: row.usdBasis, period: row.period, periodMonths: row.periodMonths ?? null, fiscalYear: row.fiscalYear,
|
|
149
|
+
nativeAmount: row.nativeAmount ?? null, nativeCurrency: row.nativeCurrency ?? null, nativeScale: row.nativeScale ?? null,
|
|
150
|
+
jurisdiction: row.jurisdiction ?? null, entityScope: row.entityScope ?? null,
|
|
151
|
+
evidenceTier: evidenceLabel(row), tier: trustTier(row), claimType: row.claimType, corroboration: row.corroboration ?? 1,
|
|
152
|
+
leadStatus: row.leadStatus ?? "none", whyUnconfirmed: row.whyUnconfirmed ?? null,
|
|
153
|
+
firstSeenAt: row.firstSeenAt, lastSeenAt: row.lastSeenAt, lastConfirmedAt: row.lastConfirmedAt,
|
|
154
|
+
source: row.sourceKind, filed: row.filedDate, confidence: row.confidence, reportingCompany: row.reportingEntity.name,
|
|
155
|
+
quote: row.quote, quoteLanguage: row.quoteLanguage, quoteGloss: row.quoteGloss ?? null, quoteGlossKind: row.quoteGloss ? "machine_translation" : null,
|
|
156
|
+
quoteMatchMode: row.quoteMatchMode, sourceUrl: row.filingUrl, filingUrl: row.filingUrl, sectionRef: row.sectionRef ?? null, sourceAttribution: row.sourceAttribution ?? null,
|
|
157
|
+
evidence: row.evidence ?? [] });
|
|
158
|
+
// --view prints that view alone and says when it is empty; left out, both views print, each only when it has rows.
|
|
159
|
+
const requested: "says" | "names" | null = args.options.view === "says" || args.options.view === "names" ? args.options.view : null;
|
|
160
|
+
const views: ("says" | "names")[] = requested ? [requested] : ["says", "names"];
|
|
161
|
+
const viewTitle = (view: "says" | "names") => view === "says" ? `${data.symbol} says` : `Names ${data.symbol}`;
|
|
162
|
+
const sections = views.flatMap((view): HeadlessBundleSection[] => {
|
|
163
|
+
const shown = (rows: SupplyRow[]) => rows.filter((row) => matchesSupplyOptions(row, options));
|
|
164
|
+
const parts = [
|
|
165
|
+
{ title: viewTitle(view), rows: shown(data[view]).filter((row) => !isUnconfirmed(row)).map(record) },
|
|
166
|
+
{ title: `${viewTitle(view)} | Unconfirmed`, rows: shown(data[view]).filter(isUnconfirmed).map(record) },
|
|
167
|
+
// Shares from before the reporter's latest period on the same basis: each dated by its own period, never current.
|
|
168
|
+
{ title: `${viewTitle(view)} | Earlier periods`, rows: shown(earlierRows(data, view)).map(record) },
|
|
169
|
+
].filter((section) => section.rows.length > 0).map((section) => ({ ...section, columns: tableColumns(section.rows, sources, data.entity?.id) }));
|
|
170
|
+
if (parts.length || !requested) return parts;
|
|
171
|
+
// "In the free preview" only when this view holds rows the preview leaves out.
|
|
172
|
+
const scope = lockedDisclosures(data, [view]) > 0 ? " in the free preview" : "";
|
|
173
|
+
return [{ title: viewTitle(view), rows: [], empty: view === "names"
|
|
174
|
+
? `No other company's disclosures name ${data.symbol}${scope}.`
|
|
175
|
+
: `${data.symbol}'s own disclosures name no relationship${scope}.` }];
|
|
176
|
+
});
|
|
177
|
+
// A requested view is complete when the preview leaves none of its own rows out.
|
|
178
|
+
const locked = lockedDisclosures(data, views);
|
|
179
|
+
const truncated = data.truncated && (!requested || locked > 0);
|
|
180
|
+
return { complete: !truncated, errors: truncated ? [data.access === "preview" ? supplyPreviewNote(data, locked) : "Additional relationships need Gloom Pro"] : [],
|
|
181
|
+
sections,
|
|
182
|
+
metadata: { symbol: data.symbol, asOf: data.asOf, view: requested ?? "both", counterparties: figures("counterparties"), locked: figures("locked"),
|
|
183
|
+
counts: data.counts, earlierCounts: data.earlierCounts ?? null, tierCounts: data.tierCounts, tiers: options.tiers, disclaimer: data.disclaimer } };
|
|
142
184
|
},
|
|
143
185
|
};
|
|
@@ -15,7 +15,7 @@ export const supplyChainModule: PluginModule = {
|
|
|
15
15
|
dispose() { supplyChainCache.reset(); graphCache.reset(); },
|
|
16
16
|
panes: [{ id: "supply-chain", name: "Supply Chain", icon: "S", component: SupplyChainPane,
|
|
17
17
|
defaultPosition: "right", defaultMode: "floating", defaultFloatingSize: { width: 130, height: 30 },
|
|
18
|
-
tickerFollower: true, tableExport: true, headless: supplyChainHeadless }],
|
|
18
|
+
tickerFollower: true, instruments: ["equity"], tableExport: true, headless: supplyChainHeadless }],
|
|
19
19
|
paneTemplates: [{ ...createTickerSurfacePaneTemplate({ id: "supply-chain-pane", paneId: "supply-chain", label: "Supply Chain",
|
|
20
20
|
description: "Pro global supply chain evidence from filings, company announcements, calls and news, with trust tiers, original quotes, native units, four-hop graphs, ranked paths and a free preview.",
|
|
21
21
|
keywords: ["supply", "supply chain", "suppliers", "customers", "concentration", "filings", "earnings calls", "news", "evidence", "global", "Korea", "Japan", "Taiwan", "graph", "paths", "Pro"], shortcut: "SPLC", shortcutAliases: ["SUPPLY"],
|
|
@@ -2,6 +2,7 @@ import type { SupplyChainPayload, SupplyOptions, SupplyRole, SupplyRow } from ".
|
|
|
2
2
|
import { SERIES_COLORS } from "../../../theme/series-colors";
|
|
3
3
|
import { revenueAmount } from "../revenue-breakdown/model";
|
|
4
4
|
import { countOf, freePreviewNote } from "../shared/free-preview";
|
|
5
|
+
import { entityTicker } from "./graph-model";
|
|
5
6
|
import { activeRelationship, corroborationLabel, evidenceDate, evidenceLabel, isUnconfirmed, matchesSupplyOptions, trustTier } from "./trust";
|
|
6
7
|
|
|
7
8
|
/** One colour per role from the shared series palette, the same in the table, the flow and the evidence. */
|
|
@@ -43,7 +44,7 @@ export function scopeWords(scope: string): string {
|
|
|
43
44
|
*/
|
|
44
45
|
export function shareParts(row: SupplyRow, focusId?: string | null, { includeReporter = false }: { includeReporter?: boolean } = {}): { value: string; basis: string } | null {
|
|
45
46
|
if (row.pctOfRevenue === null || row.pctBasis === null || trustTier(row) !== 1 || isUnconfirmed(row) || !activeRelationship(row)) return null;
|
|
46
|
-
const reporter = includeReporter || (focusId && row.reportingEntity.id !== focusId) ? `${row.reportingEntity
|
|
47
|
+
const reporter = includeReporter || (focusId && row.reportingEntity.id !== focusId) ? `${entityTicker(row.reportingEntity) ?? row.reportingEntity.name} ` : "";
|
|
47
48
|
const scope = row.pctScope ? scopeWords(row.pctScope) : "";
|
|
48
49
|
const basis = row.pctBasis === "cost" ? "cost of sales" : row.pctBasis;
|
|
49
50
|
// XBRL dimensions can qualify the numerator, denominator, or both. NVDA's
|
|
@@ -55,6 +56,25 @@ export function shareParts(row: SupplyRow, focusId?: string | null, { includeRep
|
|
|
55
56
|
// Form alone does not identify a metric's duration: a 10-Q includes YTD facts.
|
|
56
57
|
return { value: `${Number(row.pctOfRevenue.toFixed(1))}%`, basis: `of ${reporter}${scoped}` };
|
|
57
58
|
}
|
|
59
|
+
/** An XBRL fact's tagged dimensions, as the filing reader stores them in place of a sentence: "ConcentrationRiskByType=CustomerConcentrationRisk;MajorCustomers=StandardChartered;". */
|
|
60
|
+
const TAGGED_DIMENSIONS = /^\s*[A-Za-z][\w.:-]*=[^;=]*(?:;\s*[A-Za-z][\w.:-]*=[^;=]*)*;?\s*$/;
|
|
61
|
+
export const isTaggedFact = (row: Pick<SupplyRow, "sourceKind" | "quote">) => row.sourceKind === "xbrl" && TAGGED_DIMENSIONS.test(row.quote);
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* What a disclosure says, in words. A sentence from the filing reads as it is;
|
|
65
|
+
* a tagged XBRL fact reads as the kind of concentration it tags, its tagged
|
|
66
|
+
* context and what the share is of: "Customer, Gold, revenue", never the
|
|
67
|
+
* dimension names.
|
|
68
|
+
*/
|
|
69
|
+
export function disclosureText(row: Pick<SupplyRow, "sourceKind" | "quote" | "pctScope" | "pctBasis">): string {
|
|
70
|
+
if (!isTaggedFact(row)) return row.quote;
|
|
71
|
+
const type = /(?:^|;)\s*ConcentrationRiskByType=([^;]*)/.exec(row.quote)?.[1]?.replace(/^.*:/, "").replace(/ConcentrationRisk(Member)?$/, "") ?? "";
|
|
72
|
+
const kind = type.replace(/([a-z])([A-Z])/g, "$1 $2").trim();
|
|
73
|
+
const basis = row.pctBasis === "cost" ? "cost of sales" : row.pctBasis;
|
|
74
|
+
return [kind ? kind[0]!.toUpperCase() + kind.slice(1).toLowerCase() : null, row.pctScope ? scopeWords(row.pctScope) : null, basis]
|
|
75
|
+
.filter((part): part is string => !!part).join(", ") || "Tagged in the filing";
|
|
76
|
+
}
|
|
77
|
+
|
|
58
78
|
export function counterpartyName(row: SupplyRow): string {
|
|
59
79
|
if (row.counterparty.aggregate) return `Group: ${row.counterparty.name.replace(/^Undisclosed customer \((.+)\)$/i, "$1")}`;
|
|
60
80
|
if (!row.counterparty.anonymous) return row.counterparty.name;
|
|
@@ -78,22 +98,32 @@ export interface SupplyRoleCount { role: SupplyRole; counterparties: number; loc
|
|
|
78
98
|
* a free preview withholds is reported apart as locked disclosures rather
|
|
79
99
|
* than added to the companies.
|
|
80
100
|
*/
|
|
81
|
-
export function supplyRoleCounts(data: Pick<SupplyChainPayload, "says" | "names" | "counts">, views: readonly ("says" | "names")[], options: Required<SupplyOptions>): SupplyRoleCount[] {
|
|
101
|
+
export function supplyRoleCounts(data: Pick<SupplyChainPayload, "says" | "names" | "counts" | "earlier" | "earlierCounts">, views: readonly ("says" | "names")[], options: Required<SupplyOptions>): SupplyRoleCount[] {
|
|
82
102
|
return SUPPLY_ROLE_ORDER.map((role) => {
|
|
83
103
|
const companies = new Set<string>();
|
|
84
104
|
let locked = 0;
|
|
85
105
|
for (const view of views) {
|
|
86
106
|
const rows = data[view].filter((row) => row.role === role);
|
|
87
107
|
for (const row of rows) if (!row.counterparty.aggregate && !isUnconfirmed(row) && matchesSupplyOptions(row, options)) companies.add(row.counterparty.id);
|
|
88
|
-
locked += Math.max(0, data.counts[view][role] - rows.length)
|
|
108
|
+
locked += Math.max(0, data.counts[view][role] - rows.length)
|
|
109
|
+
+ Math.max(0, (data.earlierCounts?.[view][role] ?? 0) - earlierRows(data, view).filter((row) => row.role === role).length);
|
|
89
110
|
}
|
|
90
111
|
return { role, counterparties: companies.size, locked };
|
|
91
112
|
}).filter((entry) => entry.counterparties > 0 || entry.locked > 0);
|
|
92
113
|
}
|
|
93
114
|
|
|
115
|
+
/**
|
|
116
|
+
* A view's shares from before the latest period their reporter disclosed on
|
|
117
|
+
* the same basis: dated, listed apart from the current rows and never counted
|
|
118
|
+
* as current counterparties. Empty from servers that do not split them.
|
|
119
|
+
*/
|
|
120
|
+
export const earlierRows = (data: Pick<SupplyChainPayload, "earlier">, view: "says" | "names"): SupplyRow[] => data.earlier?.[view] ?? [];
|
|
121
|
+
|
|
94
122
|
/** Disclosures a free preview withholds from these views: the server's counts less the rows it sent. */
|
|
95
|
-
export function lockedDisclosures(data: Pick<SupplyChainPayload, "says" | "names" | "counts">, views: readonly ("says" | "names")[]): number {
|
|
96
|
-
|
|
123
|
+
export function lockedDisclosures(data: Pick<SupplyChainPayload, "says" | "names" | "counts" | "earlier" | "earlierCounts">, views: readonly ("says" | "names")[]): number {
|
|
124
|
+
const total = (counts: Record<SupplyRole, number> | undefined) => Object.values(counts ?? {}).reduce((a, b) => a + b, 0);
|
|
125
|
+
return views.reduce((sum, view) => sum + Math.max(0, total(data.counts[view]) - data[view].length)
|
|
126
|
+
+ Math.max(0, total(data.earlierCounts?.[view]) - earlierRows(data, view).length), 0);
|
|
97
127
|
}
|
|
98
128
|
|
|
99
129
|
/** The lock line of a free preview, in the same words in the pane and `fn SPLC`. */
|
|
@@ -111,16 +141,32 @@ export const nativeValue = (row: SupplyRow) => row.nativeAmount == null || !row.
|
|
|
111
141
|
export const disclosedValue = (row: SupplyRow) => nativeValue(row) ?? dollars(row);
|
|
112
142
|
const QUOTE_LANGUAGES: Record<string, string> = { ko: "Korean", ja: "Japanese", zh: "Chinese", "zh-TW": "Chinese", "zh-Hant": "Chinese", "zh-Hans": "Chinese", en: "English" };
|
|
113
143
|
export const quoteLanguageLabel = (row: Pick<SupplyRow, "quoteLanguage">) => QUOTE_LANGUAGES[row.quoteLanguage ?? ""] ?? row.quoteLanguage ?? "original language";
|
|
144
|
+
/**
|
|
145
|
+
* How long a period is, in the words the KPI pane uses for a period's kind:
|
|
146
|
+
* a share of receivables is a balance at the period end, an instant. Null
|
|
147
|
+
* when the source does not say; a form or a period label never does.
|
|
148
|
+
*/
|
|
149
|
+
function periodLength(months: number | null | undefined): string | null {
|
|
150
|
+
if (months == null) return null;
|
|
151
|
+
return months === 0 ? "instant" : months === 3 ? "quarter" : months === 6 ? "half" : months === 12 ? "year" : `${months} month${months === 1 ? "" : "s"}`;
|
|
152
|
+
}
|
|
153
|
+
/** The period end with its length when the source states it: 2026-07-31 half. */
|
|
154
|
+
export const periodText = (row: Pick<SupplyRow, "period" | "periodMonths">) => {
|
|
155
|
+
const length = periodLength(row.periodMonths);
|
|
156
|
+
return length ? `${row.period} ${length}` : row.period;
|
|
157
|
+
};
|
|
114
158
|
export const sourceLabel = (row: SupplyRow) => row.sourceKind === "xbrl" ? "XBRL" : row.sourceKind === "filing_text" ? row.form ?? "Filing" : row.sourceKind === "call" ? "Call" : row.sourceKind === "news" ? "News" : row.sourceKind === "press_release" ? "Release" : row.sourceKind === "web" ? "Web" : "Disclosure";
|
|
115
159
|
export function cellText(row: SupplyRow, column: string): string {
|
|
116
|
-
return column === "name" ? counterpartyName(row) : column === "ticker" ? row.counterparty
|
|
160
|
+
return column === "name" ? counterpartyName(row) : column === "ticker" ? entityTicker(row.counterparty) ?? "--"
|
|
117
161
|
: column === "role" ? roleLabel(row.role) : column === "direction" ? row.direction === "in" ? "In" : row.direction === "out" ? "Out" : "Both"
|
|
118
|
-
: column === "pct" ? percentage(row) : column === "usd" ? disclosedValue(row) : column === "fy" ? row
|
|
162
|
+
: column === "pct" ? percentage(row) : column === "usd" ? disclosedValue(row) : column === "fy" ? periodText(row)
|
|
119
163
|
: column === "publisher" ? row.evidence?.find((item) => item.status === "active")?.publisher ?? row.reportingEntity.name
|
|
120
164
|
: column === "corroboration" ? corroborationLabel(row)
|
|
121
165
|
: column === "evidence" ? evidenceLabel(row) : column === "source" ? sourceLabel(row) : column === "filed" ? evidenceDate(row) : `${Math.round(row.confidence * 100)}%`;
|
|
122
166
|
}
|
|
123
167
|
export type SupplySort = { column: string; direction: "asc" | "desc" };
|
|
168
|
+
/** Shares of different bases never rank against each other: revenue first, receivables last. */
|
|
169
|
+
const SHARE_BASIS_ORDER: readonly SupplyRow["pctBasis"][] = ["revenue", "cost", "purchases", "receivables"];
|
|
124
170
|
export function sortRows(rows: SupplyRow[], sort: SupplySort): SupplyRow[] {
|
|
125
171
|
const value = (row: SupplyRow): string | number | null => sort.column === "pct" ? row.pctOfRevenue : sort.column === "usd" ? row.nativeAmount != null ? row.nativeAmount * (row.nativeScale ?? 1) : row.usd
|
|
126
172
|
: sort.column === "confidence" ? row.confidence : sort.column === "evidence" ? trustTier(row) : cellText(row, sort.column).toLowerCase();
|
|
@@ -131,6 +177,11 @@ export function sortRows(rows: SupplyRow[], sort: SupplySort): SupplyRow[] {
|
|
|
131
177
|
const difference = currency(a).localeCompare(currency(b));
|
|
132
178
|
if (difference) return difference;
|
|
133
179
|
}
|
|
180
|
+
// Group bases before comparing shares: 30% of receivables is not more than 21% of revenue.
|
|
181
|
+
if (sort.column === "pct" && x !== null && y !== null) {
|
|
182
|
+
const difference = SHARE_BASIS_ORDER.indexOf(a.pctBasis) - SHARE_BASIS_ORDER.indexOf(b.pctBasis);
|
|
183
|
+
if (difference) return difference;
|
|
184
|
+
}
|
|
134
185
|
return x === null || y === null ? x === y ? 0 : x === null ? 1 : -1
|
|
135
186
|
: x === y ? a.id.localeCompare(b.id) : (x < y ? -1 : 1) * (sort.direction === "asc" ? 1 : -1); });
|
|
136
187
|
}
|
|
@@ -158,17 +209,27 @@ export function flowBands(rows: SupplyRow[], limit: number, pages: Partial<Recor
|
|
|
158
209
|
}
|
|
159
210
|
return Object.fromEntries((Object.keys(grouped) as FlowBand[]).map((band) => {
|
|
160
211
|
const values = sortRows(grouped[band], { column: "pct", direction: "desc" });
|
|
161
|
-
// One reporter, period and revenue scope form a compatible percentage scale
|
|
212
|
+
// One reporter, period and revenue scope form a compatible percentage scale,
|
|
213
|
+
// and a quarter and a half ending on that date do not: each stated length
|
|
214
|
+
// is its own scale, which a share whose length is not stated can join.
|
|
162
215
|
// Prefer the largest compatible group, then whole-company revenue on a tie.
|
|
163
|
-
const revenueGroups = new Map<string, SupplyRow[]>();
|
|
216
|
+
const revenueGroups = new Map<string, { length: number | null; rows: SupplyRow[] }>();
|
|
217
|
+
const unstated = new Map<string, SupplyRow[]>();
|
|
164
218
|
for (const row of values) if (trustTier(row) === 1 && band === "customers" && row.pctBasis === "revenue" && !(row.sourceKind === "xbrl" && row.pctScope) && (row.pctOfRevenue ?? 0) > 0 && (!focusId || row.reportingEntity.id === focusId)) {
|
|
165
|
-
const key = revenueKey(row);
|
|
166
|
-
|
|
219
|
+
const key = revenueKey(row), length = row.periodMonths ?? null;
|
|
220
|
+
if (length === null) unstated.set(key, [...(unstated.get(key) ?? []), row]);
|
|
221
|
+
else revenueGroups.set(`${key}:${length}`, { length, rows: [...(revenueGroups.get(`${key}:${length}`)?.rows ?? []), row] });
|
|
222
|
+
}
|
|
223
|
+
for (const [key, rows] of unstated) {
|
|
224
|
+
const stated = [...revenueGroups.values()].filter((group) => revenueKey(group.rows[0]!) === key);
|
|
225
|
+
for (const group of stated) group.rows.push(...rows);
|
|
226
|
+
if (!stated.length) revenueGroups.set(key, { length: null, rows });
|
|
167
227
|
}
|
|
168
|
-
const revenueGroup = [...revenueGroups.values()].sort((a, b) => b.length - a.length || Number(a[0]!.pctScope !== null) - Number(b[0]!.pctScope !== null))[0];
|
|
169
|
-
const scaleKey = revenueGroup ? revenueKey(revenueGroup[0]!) : null;
|
|
228
|
+
const revenueGroup = [...revenueGroups.values()].sort((a, b) => b.rows.length - a.rows.length || Number(a.rows[0]!.pctScope !== null) - Number(b.rows[0]!.pctScope !== null))[0];
|
|
229
|
+
const scaleKey = revenueGroup ? revenueKey(revenueGroup.rows[0]!) : null;
|
|
170
230
|
const value = (row: SupplyRow) => trustTier(row) !== 1 ? 0 : scaleKey === null ? row.usd ?? 0
|
|
171
|
-
: row.pctBasis === "revenue" && !(row.sourceKind === "xbrl" && row.pctScope) && revenueKey(row) === scaleKey
|
|
231
|
+
: row.pctBasis === "revenue" && !(row.sourceKind === "xbrl" && row.pctScope) && revenueKey(row) === scaleKey
|
|
232
|
+
&& (row.periodMonths == null || revenueGroup!.length === null || row.periodMonths === revenueGroup!.length) ? row.pctOfRevenue ?? 0 : 0;
|
|
172
233
|
// Use the entire band: paging must not change an existing ribbon's width.
|
|
173
234
|
const max = Math.max(0, ...values.map(value));
|
|
174
235
|
const ordered = [...values].sort((a, b) => value(b) - value(a));
|
|
@@ -176,7 +237,7 @@ export function flowBands(rows: SupplyRow[], limit: number, pages: Partial<Recor
|
|
|
176
237
|
const start = paged ? ((pages[band] ?? 0) % Math.ceil(values.length / pageSize)) * pageSize : 0;
|
|
177
238
|
const visible = ordered.slice(start, start + (paged ? pageSize : limit));
|
|
178
239
|
const nodes: FlowNode[] = visible.map((row) => ({ id: row.id, label: counterpartyName(row), row, band, more: 0,
|
|
179
|
-
weight: value(row) > 0 ? value(row) / max : null, weightScope: revenueGroup?.[0]?.pctScope ?? null, weightBasis: scaleKey ? "revenue" : max > 0 ? "usd" : null }));
|
|
240
|
+
weight: value(row) > 0 ? value(row) / max : null, weightScope: revenueGroup?.rows[0]?.pctScope ?? null, weightBasis: scaleKey ? "revenue" : max > 0 ? "usd" : null }));
|
|
180
241
|
if (paged) nodes.push({ id: `more:${band}`, label: `+${values.length - visible.length} more`, row: null, band, more: values.length - visible.length, weight: null, weightScope: null, weightBasis: null });
|
|
181
242
|
return [band, nodes];
|
|
182
243
|
})) as Record<FlowBand, FlowNode[]>;
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
import { ClippedText } from "../../../components/ui/display";
|
|
12
12
|
import { RatioBar } from "../../../components/ui/ratio-bar";
|
|
13
13
|
import { getTableWidth } from "../../../components/ui/table-layout";
|
|
14
|
+
import { chromeBarRows } from "../../../components/layout/pane/sizing";
|
|
14
15
|
import { usePaneRefreshKey } from "../../../components/data-table/table-pane";
|
|
15
16
|
import { useAsyncResource, useAutoRefresh, usePaneSettingValue, usePluginAppActions, usePluginPaneState } from "../../../public/react";
|
|
16
17
|
import { usePaneTickerIdentity } from "../../../state/hooks/pane-ticker";
|
|
@@ -27,8 +28,9 @@ import { cachedSupplyChain, loadSupplyChain, SUPPLY_UNAVAILABLE, validateSupplyC
|
|
|
27
28
|
import { useSupplyEvidence } from "./evidence";
|
|
28
29
|
import { SupplyFlow } from "./flow";
|
|
29
30
|
import { SupplyGraphPane } from "./graph-pane";
|
|
31
|
+
import { entityTicker } from "./graph-model";
|
|
30
32
|
import {
|
|
31
|
-
cellText, counterpartyKind, counterpartyKindLabel, counterpartyLabel, counterpartyName, disclosedValue, lockedDisclosures, nativeValue, percentage, ROLE_COLORS, roleLabel,
|
|
33
|
+
cellText, counterpartyKind, counterpartyKindLabel, counterpartyLabel, counterpartyName, disclosedValue, earlierRows, lockedDisclosures, nativeValue, percentage, ROLE_COLORS, roleLabel,
|
|
32
34
|
shareParts, sortRows, supplyPreviewNote, supplyRoleCounts, type SupplySort,
|
|
33
35
|
} from "./model";
|
|
34
36
|
import { RowEvidence } from "./row-evidence";
|
|
@@ -55,6 +57,8 @@ function shareBarCells(width: number, bases: readonly number[]): number {
|
|
|
55
57
|
}
|
|
56
58
|
const longestBasis = (bases: readonly number[], width: number) => Math.max(0, ...bases.filter((cells) => SHARE_BAR_MIN_CELLS + 1 + cells <= width));
|
|
57
59
|
|
|
60
|
+
/** A period end date; its length, when the source states it, follows it in a wider column. */
|
|
61
|
+
const PERIOD_DATE_CELLS = 10;
|
|
58
62
|
/**
|
|
59
63
|
* Columns that fit the pane, giving up the least first: the share bar shortens
|
|
60
64
|
* to keep the whole basis, the name shortens to 18 cells, the ticker folds into
|
|
@@ -64,7 +68,7 @@ const longestBasis = (bases: readonly number[], width: number) => Math.max(0, ..
|
|
|
64
68
|
* Value shows only when some row discloses a value, retaining its original
|
|
65
69
|
* currency and units.
|
|
66
70
|
*/
|
|
67
|
-
function tableColumns(width: number, desktop: boolean, locked: boolean, valueWidth: number | null, bases: readonly number[]): DataTableColumn[] {
|
|
71
|
+
function tableColumns(width: number, desktop: boolean, locked: boolean, valueWidth: number | null, bases: readonly number[], periodWidth = PERIOD_DATE_CELLS): DataTableColumn[] {
|
|
68
72
|
const wide = width >= 150, medium = width >= 110;
|
|
69
73
|
const name: DataTableColumn = { id: "name", label: "Counterparty", width: Math.max(locked && !desktop ? 34 : 0, wide ? 30 : medium ? 26 : 20), flexGrow: 1, align: "left" };
|
|
70
74
|
const share: DataTableColumn = { id: "pct", label: "Share", width: wide ? 34 : medium ? 30 : 26, align: "left" };
|
|
@@ -75,7 +79,7 @@ function tableColumns(width: number, desktop: boolean, locked: boolean, valueWid
|
|
|
75
79
|
{ id: "role", label: "Role", width: 11, align: "left" },
|
|
76
80
|
share,
|
|
77
81
|
...(valueWidth !== null ? [{ id: "usd", label: "Value", width: Math.max(medium ? 10 : 8, valueWidth), align: "right" as const }] : []),
|
|
78
|
-
{ id: "fy", label: "Period", width:
|
|
82
|
+
{ id: "fy", label: "Period", width: periodWidth, align: "left" },
|
|
79
83
|
...(wide ? [
|
|
80
84
|
{ id: "filed", label: "Published", width: 10, align: "left" as const },
|
|
81
85
|
{ id: "publisher", label: "Publisher", width: 16, align: "left" as const },
|
|
@@ -176,17 +180,21 @@ function SupplyView({ symbol, width, height, focused }: Pick<PaneProps, "width"
|
|
|
176
180
|
const allRows = useMemo(() => data ? [...data.says, ...data.names].filter((row) => matchesSupplyOptions(row, options)) : [], [data, options]);
|
|
177
181
|
const [flowIds, setFlowIds] = useState<string[]>([]);
|
|
178
182
|
const rows = useMemo(() => data ? sortRows(data[view].filter((row) => matchesSupplyOptions(row, options)), sort) : [], [data, view, sort, options]);
|
|
179
|
-
|
|
183
|
+
// Shares from before the reporter's latest period: their own section, never among the current rows or the flow.
|
|
184
|
+
const earlier = useMemo(() => data ? sortRows(earlierRows(data, view).filter((row) => matchesSupplyOptions(row, options)), sort) : [], [data, view, sort, options]);
|
|
185
|
+
const tableRows = useMemo(() => [...rows, ...earlier], [rows, earlier]);
|
|
186
|
+
const selectionRows = tab === "flow" ? allRows.filter((row) => flowIds.includes(row.id)) : tableRows;
|
|
180
187
|
const selected = tab === "flow" && selectedId?.startsWith("more:") ? null
|
|
181
188
|
: selectionRows.find((row) => row.id === selectedId) ?? (tab === "flow" ? allRows.find((row) => row.id === flowIds[0]) : rows[0]) ?? null;
|
|
182
|
-
const openRow = allRows.find((row) => row.id === openId) ?? (openingEvidence && openId === null ? rows[0] : null) ?? null;
|
|
183
|
-
useSupplyEvidence(graphTab ? null : data, tab, view, tab === "flow" ? flowIds :
|
|
189
|
+
const openRow = allRows.find((row) => row.id === openId) ?? earlier.find((row) => row.id === openId) ?? (openingEvidence && openId === null ? rows[0] : null) ?? null;
|
|
190
|
+
useSupplyEvidence(graphTab ? null : data, tab, view, tab === "flow" ? flowIds : tableRows.map((row) => row.id), openRow?.id ?? null, options.tiers);
|
|
184
191
|
const locked = data?.truncated ? lockedDisclosures(data, [view]) : 0;
|
|
185
192
|
const items = useMemo<SectionedRow<Item>[]>(() => buildSectionedRows<Item>([
|
|
186
193
|
{ label: "Relationships", items: rows.filter((row) => !isUnconfirmed(row)).map((row) => ({ kind: "edge", row })) },
|
|
187
194
|
{ label: "Unconfirmed", items: rows.filter(isUnconfirmed).map((row) => ({ kind: "edge", row })) },
|
|
195
|
+
{ label: "Earlier periods", items: earlier.map((row) => ({ kind: "edge", row })) },
|
|
188
196
|
{ label: "Pro", items: Array.from({ length: Math.min(3, locked) }, (_, i) => ({ kind: "locked", id: `locked:${i}` })) },
|
|
189
|
-
], itemId), [rows, locked]);
|
|
197
|
+
], itemId), [rows, earlier, locked]);
|
|
190
198
|
const { strip, rows: tabRows } = usePaneTabs(symbol ? { tabs: [{ value: "table", label: "Table" }, { value: "flow", label: "Flow", disabled: tooSmall }, { value: "graph", label: "Graph" }, { value: "path", label: "Path" }], activeValue: tab, onSelect: setTab, focused, dense: true } : null);
|
|
191
199
|
useAutoRefresh(resource.updatedAt, resource.load);
|
|
192
200
|
usePaneRefreshKey(() => void resource.reload(), { focused: focused && !graphTab });
|
|
@@ -217,10 +225,16 @@ function SupplyView({ symbol, width, height, focused }: Pick<PaneProps, "width"
|
|
|
217
225
|
...(savedTab === "flow" && tooSmall ? ["Flow needs a wider pane. Showing the table."] : []),
|
|
218
226
|
] });
|
|
219
227
|
const focusId = data?.entity?.id;
|
|
220
|
-
const values =
|
|
228
|
+
const values = tableRows.filter((row) => nativeValue(row) !== null || row.usd !== null);
|
|
221
229
|
const valueWidth = values.length ? Math.min(28, Math.max(...values.map((row) => displayWidth(disclosedValue(row).replace(/ (disclosed|derived)$/, ""))))) : null;
|
|
222
|
-
const bases =
|
|
223
|
-
|
|
230
|
+
const bases = tableRows.flatMap((row) => { const share = shareParts(row, focusId); return share ? [displayWidth(share.basis)] : []; });
|
|
231
|
+
// The period's length follows its end date when the source states it (2026-07-31 half) and costs
|
|
232
|
+
// no column; laid out a cell narrower, the table also clears its own scrollbar. Otherwise the
|
|
233
|
+
// evidence view says it.
|
|
234
|
+
const periodWidth = Math.max(PERIOD_DATE_CELLS, ...tableRows.map((row) => displayWidth(cellText(row, "fy"))));
|
|
235
|
+
const dated = tableColumns(width, desktop, locked > 0, valueWidth, bases);
|
|
236
|
+
const lengths = periodWidth > PERIOD_DATE_CELLS ? tableColumns(width - 1, desktop, locked > 0, valueWidth, bases, periodWidth) : null;
|
|
237
|
+
const columns = lengths?.some((column) => column.id === "fy") && lengths.map((column) => column.id).join() === dated.map((column) => column.id).join() ? lengths : dated;
|
|
224
238
|
const renderCell = (entry: SectionedRow<Item>, column: DataTableColumn, _index: number, state: { selected: boolean }): DataTableCell => {
|
|
225
239
|
if (!isSectionedItemRow(entry)) return { text: "" };
|
|
226
240
|
const item = entry.item;
|
|
@@ -245,7 +259,7 @@ function SupplyView({ symbol, width, height, focused }: Pick<PaneProps, "width"
|
|
|
245
259
|
// The desktop always says it in one word: the Role column beside it names the role, and the name takes the room.
|
|
246
260
|
const full = counterpartyKindLabel(row);
|
|
247
261
|
const kind = !desktop && full && displayWidth(counterpartyLabel(row)) + displayWidth(full) + 4 <= column.width ? full : counterpartyKindLabel(row, true);
|
|
248
|
-
const ticker = !columns.some((entry) => entry.id === "ticker") ? row.counterparty
|
|
262
|
+
const ticker = !columns.some((entry) => entry.id === "ticker") ? entityTicker(row.counterparty) : null;
|
|
249
263
|
const room = Math.max(8, column.width - (kind ? displayWidth(kind) + 4 : 0) - (ticker ? displayWidth(ticker) + 1 : 0));
|
|
250
264
|
// On the desktop the name gives way at the column's edge by CSS and the ticker and kind keep their room.
|
|
251
265
|
return { text: cellText(row, "name"), content: <Box flexDirection="row" height={1} gap={ticker ? 1 : 2} overflow="hidden" {...(desktop ? { flexShrink: 1, minWidth: 0 } : {})}>
|
|
@@ -255,7 +269,7 @@ function SupplyView({ symbol, width, height, focused }: Pick<PaneProps, "width"
|
|
|
255
269
|
</Box> };
|
|
256
270
|
}
|
|
257
271
|
case "ticker": {
|
|
258
|
-
const ticker = row.counterparty
|
|
272
|
+
const ticker = entityTicker(row.counterparty);
|
|
259
273
|
if (!ticker) return { text: "", value: null };
|
|
260
274
|
return { text: ticker, color: colors.textBright, content: desktop ? <Badge label={ticker} tone="accent" /> : undefined };
|
|
261
275
|
}
|
|
@@ -267,7 +281,7 @@ function SupplyView({ symbol, width, height, focused }: Pick<PaneProps, "width"
|
|
|
267
281
|
content: <ShareCell row={row} focusId={focusId} width={column.width} bases={bases} selected={state.selected} /> };
|
|
268
282
|
case "usd": return nativeValue(row) === null && row.usd === null ? { text: "", value: null }
|
|
269
283
|
: { text: disclosedValue(row).replace(/ (disclosed|derived)$/, ""), value: row.nativeAmount != null ? row.nativeAmount * (row.nativeScale ?? 1) : row.usd, color: colors.text };
|
|
270
|
-
case "fy": return { text: row.period, color: colors.textDim };
|
|
284
|
+
case "fy": return { text: displayWidth(cellText(row, "fy")) <= column.width ? cellText(row, "fy") : row.period, color: colors.textDim };
|
|
271
285
|
default: return { text: cellText(row, column.id) };
|
|
272
286
|
}
|
|
273
287
|
};
|
|
@@ -287,7 +301,7 @@ function SupplyView({ symbol, width, height, focused }: Pick<PaneProps, "width"
|
|
|
287
301
|
// A short flow keeps one row of figures, dropping the last roles, so the cards keep their room.
|
|
288
302
|
const flowFigures = bodyHeight < 26 ? figures.slice(0, flowFigureColumns) : figures;
|
|
289
303
|
const selectedShare = selected ? shareParts(selected, focusId) : null;
|
|
290
|
-
const flowMeta = selected ? `${selected.reportingEntity
|
|
304
|
+
const flowMeta = selected ? `${entityTicker(selected.reportingEntity) ?? selected.reportingEntity.name} ${evidenceLabel(selected)} · ${selectedShare ? `${selectedShare.value} ${selectedShare.basis}`
|
|
291
305
|
: nativeValue(selected) !== null || selected.usd !== null ? disclosedValue(selected) : `${roleLabel(selected.role)}, no figure disclosed`}` : undefined;
|
|
292
306
|
return <Box width={width} height={height} flexDirection="column">
|
|
293
307
|
{strip}
|
|
@@ -299,7 +313,7 @@ function SupplyView({ symbol, width, height, focused }: Pick<PaneProps, "width"
|
|
|
299
313
|
<QueryBar width={width} filters={[tierFilter]} meta={flowMeta} />
|
|
300
314
|
<StatGrid items={flowFigures} width={width} columns={flowFigureColumns} />
|
|
301
315
|
<SupplyFlow rows={allRows} symbol={symbol} focusName={data.entity?.name ?? null} focusId={focusId} width={width}
|
|
302
|
-
height={Math.max(10, bodyHeight -
|
|
316
|
+
height={Math.max(10, bodyHeight - chromeBarRows(desktop) - statGridRows(flowFigures, width, flowFigureColumns) - (data.truncated ? 1 : 0))} focused={focused && !openRow} selectedId={selectedId}
|
|
303
317
|
onSelect={setSelected} onOpen={navigate} onVisible={setFlowIds} />
|
|
304
318
|
{data.truncated ? <Box paddingX={1}><UpgradeLabel text="Upgrade to see every relationship" onPress={openUpgrade} role="supply-upgrade" /></Box> : null}
|
|
305
319
|
</Box> : <DataTableView<SectionedRow<Item>> columns={columns}
|
|
@@ -6,7 +6,7 @@ import { scrollByLines } from "../../../state/pane-scroll-registry";
|
|
|
6
6
|
import { useThemeColors } from "../../../theme/theme-context";
|
|
7
7
|
import { Box, Text, useUiCapabilities, type ScrollBoxRenderable } from "../../../ui";
|
|
8
8
|
import { isPlainKey } from "../../../utils/keyboard";
|
|
9
|
-
import { counterpartyKind, counterpartyKindLabel, disclosedValue, dollars, nativeValue, ROLE_COLORS, roleLabel, shareParts, sourceLabel } from "./model";
|
|
9
|
+
import { counterpartyKind, counterpartyKindLabel, disclosedValue, disclosureText, dollars, isTaggedFact, nativeValue, periodText, ROLE_COLORS, roleLabel, shareParts, sourceLabel } from "./model";
|
|
10
10
|
import { canShowQuote, corroborationLabel, evidenceDate, evidenceLabel, isUnconfirmed, tierLabel } from "./trust";
|
|
11
11
|
import { DisclosureQuote } from "./disclosure-quote";
|
|
12
12
|
|
|
@@ -49,7 +49,7 @@ export function SupplySources({ row, width, onOpenSource }: { row: SupplyRow; wi
|
|
|
49
49
|
</Section>) : <>
|
|
50
50
|
<KeyValueRow label="Disclosure" value={`${sourceLabel(row)} · filed ${row.filedDate ?? "--"}`} labelWidth={20} />
|
|
51
51
|
{row.quoteMatchMode ? <KeyValueRow label="Evidence match" value={row.quoteMatchMode === "exact" ? "Exact text" : row.quoteMatchMode === "whitespace" ? "Whitespace normalized" : "Unicode and whitespace normalized"} labelWidth={20} /> : null}
|
|
52
|
-
<DisclosureQuote role={row.role} quote={row
|
|
52
|
+
<DisclosureQuote role={row.role} quote={disclosureText(row)} quoteLanguage={row.quoteLanguage} width={width} label={isTaggedFact(row) ? "Tagged in the filing" : undefined} />
|
|
53
53
|
{row.quoteGloss ? <SourceGloss text={row.quoteGloss} width={width} /> : null}
|
|
54
54
|
{sourceLink(row.filingUrl, `Open ${row.form ?? "filing"}${row.filedDate ? ` filed ${row.filedDate}` : ""}`, `Open ${row.form ?? "source"} filing`)}
|
|
55
55
|
</>}
|
|
@@ -72,7 +72,7 @@ export function RowEvidence({ row, focusId, width, height, focused }: { row: Sup
|
|
|
72
72
|
const figures: StatItem[] = [
|
|
73
73
|
...(share ? [{ id: "share", label: "Share", value: share.value, detail: share.basis }] : []),
|
|
74
74
|
...(native || row.usd !== null ? [{ id: "value", label: "Value", value: disclosedValue(row) }] : []),
|
|
75
|
-
{ id: "period", label: "Period", value: row
|
|
75
|
+
{ id: "period", label: "Period", value: periodText(row), detail: row.fiscalYear ? `Fiscal year ${row.fiscalYear}` : undefined },
|
|
76
76
|
{ id: "published", label: "Published", value: evidenceDate(row), detail: evidenceLabel(row) },
|
|
77
77
|
{ id: "confidence", label: "Confidence", value: `${Math.round(row.confidence * 100)}%` },
|
|
78
78
|
];
|
|
@@ -80,7 +80,8 @@ export function RowEvidence({ row, focusId, width, height, focused }: { row: Sup
|
|
|
80
80
|
return <Box width={width} height={desktop ? undefined : height} flexGrow={1} flexBasis={0} minHeight={0}>
|
|
81
81
|
<DetailScrollBody ref={scrollRef} resetScrollKey={row.id}>
|
|
82
82
|
<StatGrid items={figures} width={width} />
|
|
83
|
-
|
|
83
|
+
{/* The desktop's detail body already holds the pane's inset. */}
|
|
84
|
+
<Box flexDirection="column" paddingX={desktop ? 0 : 1} paddingTop={1}>
|
|
84
85
|
<Box flexDirection="row" gap={1}><Badge tone={isUnconfirmed(row) ? "neutral" : "accent"} label={evidenceLabel(row)} />
|
|
85
86
|
{row.leadStatus === "verified" ? <Badge tone="positive" label="Verified" /> : null}</Box>
|
|
86
87
|
<KeyValueRow label="Reporting company" value={row.reportingEntity.name} labelWidth={20} />
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { THEME_PERIODS, type ThemeAggregate, type ThemeMember, type ThemePeriod, type ThemeSummary } from "../../../api-client/themes";
|
|
2
2
|
import type { DataTableColumn } from "../../../components";
|
|
3
|
-
import { getTableWidth } from "../../../components/ui/table-layout";
|
|
3
|
+
import { dropColumnsToFit, getTableWidth } from "../../../components/ui/table-layout";
|
|
4
4
|
import { extendedSessionStateLabel, type ExtendedSession } from "../../../market-data/market/status";
|
|
5
5
|
import { compareSortValues, type SortDirection } from "../../../utils/sort-values";
|
|
6
6
|
|
|
@@ -136,11 +136,8 @@ export function memberColumns(width: number, extendedSessions: readonly Extended
|
|
|
136
136
|
["return3MPercent", "returnYtdPercent", "return1MPercent", "return1WPercent", "preMarket", "afterHours", "name", "price"]);
|
|
137
137
|
}
|
|
138
138
|
function fitColumns(columns: DataTableColumn[], width: number, drop: string[]): DataTableColumn[] {
|
|
139
|
+
columns = dropColumnsToFit(columns, width, drop);
|
|
139
140
|
const used = () => getTableWidth(columns);
|
|
140
|
-
for (const id of drop) {
|
|
141
|
-
if (used() <= width) break;
|
|
142
|
-
columns = columns.filter((col) => col.id !== id);
|
|
143
|
-
}
|
|
144
141
|
const name = columns.find((col) => col.id === "name") ?? columns[0]!;
|
|
145
142
|
const spare = width - used();
|
|
146
143
|
name.width = Math.max(8, name.width + Math.min(spare, Math.max(0, 36 - name.width)));
|