gloomberb 0.18.2 → 0.18.4
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 +8 -8
- package/README.zh-CN.md +11 -11
- package/bin/{gloomberb → gloom} +3 -1
- package/package.json +6 -2
- package/patches/electrobun@1.18.1.patch +106 -5
- package/src/account/checkout-handoff.tsx +225 -0
- package/src/account/device-signin-dialog.tsx +2 -2
- package/src/account/device-signin.ts +2 -2
- package/src/account/upgrade-dialog.tsx +1 -1
- package/src/api-client/askg.ts +2 -2
- package/src/api-client/auth.ts +2 -2
- package/src/api-client/central-bank-rates.ts +6 -0
- package/src/api-client/collections.ts +5 -1
- package/src/api-client/cot.ts +2 -0
- package/src/api-client/crypto-etf-flows.ts +37 -0
- package/src/api-client/crypto-markets.ts +60 -0
- package/src/api-client/data.ts +99 -5
- package/src/api-client/doe.ts +15 -0
- package/src/api-client/equity-screener.ts +28 -0
- package/src/api-client/exchange-announcements.ts +38 -0
- package/src/api-client/fund-facts.ts +39 -0
- package/src/api-client/futures-curve.ts +9 -1
- package/src/api-client/hiring.ts +301 -0
- package/src/api-client/index.ts +24 -5
- package/src/api-client/market-discovery.ts +14 -0
- package/src/api-client/members.ts +6 -0
- package/src/api-client/mna.ts +6 -0
- package/src/api-client/paths.ts +18 -1
- package/src/api-client/request.ts +26 -7
- package/src/api-client/short-side-publications.ts +37 -0
- package/src/api-client/socket.ts +64 -4
- package/src/api-client/swap-curve.ts +35 -0
- package/src/api-client/telemetry.ts +17 -0
- package/src/api-client/themes.ts +7 -1
- package/src/api-client/types.ts +90 -2
- package/src/app/global-shortcuts.ts +1 -16
- package/src/app/pane-runtime/plugin-bindings.ts +9 -2
- package/src/app/runtime/desktop-deeplink.ts +5 -5
- package/src/app/runtime/plugin-bindings.ts +2 -2
- package/src/app/runtime/startup.ts +13 -0
- package/src/app/runtime/update.ts +28 -8
- package/src/app/star-prompt/status-line.tsx +2 -2
- package/src/architecture/core-builtin-allowlist.json +5 -2
- package/src/architecture/pane-tabs-allowlist.json +65 -0
- package/src/architecture/ui-literals-allowlist.json +3 -3
- package/src/architecture/ui-tokens-allowlist.json +1 -1
- package/src/brokers/broker-portfolio-sync.ts +37 -0
- package/src/brokers/directory.ts +11 -0
- package/src/brokers/logos.ts +3 -1
- package/src/brokers/signed-in/adapter.ts +304 -26
- package/src/brokers/signed-in/client.ts +14 -2
- package/src/brokers/signed-in/connect.ts +10 -2
- package/src/brokers/sync-broker-instance.ts +9 -1
- package/src/capabilities/chart-series.ts +22 -6
- package/src/cli/bank-section.ts +1 -1
- package/src/cli/base-converter.ts +23 -14
- package/src/cli/central-bank-events.ts +1 -1
- package/src/cli/command-options.ts +59 -4
- package/src/cli/commands/api.ts +9 -6
- package/src/cli/commands/broker.ts +2 -2
- package/src/cli/commands/command-utils.ts +2 -2
- package/src/cli/commands/crypto-hints.ts +7 -20
- package/src/cli/commands/fred-series.ts +4 -2
- package/src/cli/commands/keybindings.ts +2 -2
- package/src/cli/commands/market.ts +1189 -296
- package/src/cli/commands/news-hints.ts +2 -2
- package/src/cli/commands/news-search.ts +59 -6
- package/src/cli/commands/options-leaps.ts +41 -26
- package/src/cli/commands/overview.ts +121 -48
- package/src/cli/commands/plugins.ts +9 -9
- package/src/cli/commands/remote.ts +13 -10
- package/src/cli/commands/search.ts +64 -44
- package/src/cli/commands/system.ts +27 -19
- package/src/cli/commands/themes.ts +1 -1
- package/src/cli/commands/ticker.ts +272 -70
- package/src/cli/context.ts +3 -2
- package/src/cli/desktop-pane-shot-view.ts +2 -2
- package/src/cli/desktop-pane-shot.ts +1 -1
- package/src/cli/earnings-calendar.ts +4 -4
- package/src/cli/entry.ts +18 -1
- package/src/cli/errors.ts +20 -2
- package/src/cli/exit-codes.ts +1 -1
- package/src/cli/export-source.ts +10 -4
- package/src/cli/freshness.ts +2 -8
- package/src/cli/fx-forward.ts +130 -0
- package/src/cli/fx-pair.ts +10 -9
- package/src/cli/glossary.ts +64 -20
- package/src/cli/help.ts +20 -14
- package/src/cli/history-export.ts +126 -0
- package/src/cli/history-rows.ts +196 -43
- package/src/cli/index-roots.ts +5 -45
- package/src/cli/index.ts +32 -18
- package/src/cli/issuer-membership.ts +103 -0
- package/src/cli/known-gaps.ts +118 -25
- package/src/cli/listing-arg.ts +315 -43
- package/src/cli/name-entries.ts +73 -22
- package/src/cli/native-smoke.ts +2 -0
- package/src/cli/not-a-ticker.ts +19 -9
- package/src/cli/opentui-libc.ts +5 -0
- package/src/cli/options.ts +12 -0
- package/src/cli/pane-functions/capabilities.ts +77 -20
- package/src/cli/pane-functions/catalog.ts +40 -23
- package/src/cli/pane-functions/discovery.ts +1 -1
- package/src/cli/pane-functions/dom.ts +12 -8
- package/src/cli/pane-functions/financial-ratio-shot.ts +2 -2
- package/src/cli/pane-functions/freshness.ts +174 -23
- package/src/cli/pane-functions/function-help.ts +66 -27
- package/src/cli/pane-functions/headless.ts +48 -16
- package/src/cli/pane-functions/index.ts +82 -21
- package/src/cli/pane-functions/options.ts +22 -2
- package/src/cli/pane-functions/report-notices.ts +12 -4
- package/src/cli/pane-functions/report.ts +5 -5
- package/src/cli/pane-functions/resolver.ts +65 -14
- package/src/cli/pane-functions/screenshot-assessment.ts +322 -0
- package/src/cli/pane-functions/screenshot-bridge.ts +152 -0
- package/src/cli/pane-functions/screenshot-chart-evidence.ts +396 -0
- package/src/cli/pane-functions/screenshot-data-evidence.ts +383 -0
- package/src/cli/pane-functions/screenshot-evidence.ts +1 -1
- package/src/cli/pane-functions/screenshot-payload.ts +453 -0
- package/src/cli/pane-functions/screenshot-render.ts +316 -0
- package/src/cli/pane-functions/screenshot-types.ts +162 -0
- package/src/cli/pane-functions/shot-options.ts +8 -3
- package/src/cli/peso-dollar-rates.ts +79 -0
- package/src/cli/quote-answer.ts +38 -3
- package/src/cli/report-tables.ts +190 -27
- package/src/cli/restore-plugins.ts +29 -14
- package/src/cli/result.ts +122 -25
- package/src/cli/series-search.ts +5 -5
- package/src/cli/statement-filings.ts +19 -0
- package/src/cli/suffixed-listing-rows.ts +49 -0
- package/src/cli/symbol-args.ts +50 -15
- package/src/cli/symbol-cells.ts +120 -0
- package/src/cli/symbol-list.ts +226 -60
- package/src/cli/symbol-rows.ts +131 -25
- package/src/cli/ticker-resolution.ts +108 -11
- package/src/cli/treasury-yields.ts +5 -5
- package/src/cli/types.ts +2 -0
- package/src/cli/uncovered-instrument.ts +3 -3
- package/src/cli/unknown-command.ts +6 -6
- package/src/components/chart/composite/chart-layout.ts +131 -0
- package/src/components/chart/composite/composite-chart.tsx +387 -21
- package/src/components/chart/composite/drawing-store.ts +26 -6
- package/src/components/chart/composite/interactions.ts +9 -3
- package/src/components/chart/composite/legend.tsx +75 -3
- package/src/components/chart/composite/levels.ts +5 -0
- package/src/components/chart/composite/panel-gestures.ts +41 -0
- package/src/components/chart/composite/panel-labels.ts +2 -1
- package/src/components/chart/composite/panel-surface.tsx +316 -11
- package/src/components/chart/composite/price-axis-labels.tsx +27 -3
- package/src/components/chart/composite/rasterizer.ts +44 -19
- package/src/components/chart/composite/scene.ts +16 -4
- package/src/components/chart/composite/text-renderer.ts +48 -21
- package/src/components/chart/composite/toolbar.tsx +52 -5
- package/src/components/chart/composite/types.ts +19 -0
- package/src/components/chart/composite/use-composite-chart-keyboard.ts +120 -13
- package/src/components/chart/composite/use-composite-value-scales.ts +44 -0
- package/src/components/chart/composite/use-composite-viewport.ts +12 -3
- package/src/components/chart/composite/value-scale.ts +149 -0
- package/src/components/chart/composite/volume-profile-paint.ts +6 -3
- package/src/components/chart/core/pointer.ts +2 -0
- package/src/components/chart-table/index.ts +2 -0
- package/src/components/chart-table/read.tsx +74 -0
- package/src/components/command-bar/commands/collection-list.ts +41 -19
- package/src/components/command-bar/commands/collection.ts +9 -3
- package/src/components/command-bar/commands/direct/index.ts +1 -1
- package/src/components/command-bar/commands/direct/runtime.ts +3 -2
- package/src/components/command-bar/pane-templates/items.ts +59 -6
- package/src/components/command-bar/pane-templates/workflow.ts +10 -1
- package/src/components/command-bar/routes/root/command-items.ts +32 -6
- package/src/components/command-bar/routes/root/plugin-install.ts +1 -1
- package/src/components/command-bar/routes/root/provider-search.ts +42 -11
- package/src/components/command-bar/routes/root/results.ts +18 -4
- package/src/components/command-bar/routes/root/runtime.ts +15 -3
- package/src/components/command-bar/routes/root/search-providers.ts +25 -2
- package/src/components/command-bar/routes/root/selection.ts +6 -1
- package/src/components/command-bar/routes/root/shortcut-feedback.ts +4 -1
- package/src/components/command-bar/routes/root/shortcuts.ts +30 -3
- package/src/components/command-bar/routes/ticker-search/results.ts +73 -4
- package/src/components/command-bar/selection-runtime.ts +50 -10
- package/src/components/command-bar/surface/index.tsx +24 -2
- package/src/components/command-bar/view-model.ts +7 -0
- package/src/components/command-bar/workflow/broker.ts +2 -2
- package/src/components/command-bar/workflow/collection-actions.ts +46 -7
- package/src/components/command-bar/workflow/collection-ticker.ts +32 -4
- package/src/components/command-bar/workflow/fields.ts +8 -2
- package/src/components/command-bar/workflow/ops.ts +18 -4
- package/src/components/command-bar/workflow/portfolio-position.ts +53 -4
- package/src/components/command-bar/workflow/submit.ts +3 -2
- package/src/components/command-bar/workflow/tickers.ts +5 -1
- package/src/components/company-logo.tsx +39 -0
- package/src/components/data-table/sections.ts +4 -2
- package/src/components/data-table/view.tsx +23 -3
- package/src/components/form-modal/confirm.tsx +2 -1
- package/src/components/form-modal/request.ts +5 -0
- package/src/components/form-modal/routes.ts +4 -1
- package/src/components/index.ts +13 -6
- package/src/components/layout/detached-pane-shell.tsx +1 -0
- package/src/components/layout/floating-pane.tsx +1 -0
- package/src/components/layout/header.tsx +234 -60
- package/src/components/layout/market-summary.ts +9 -6
- package/src/components/layout/pane/capture-status.ts +1 -1
- package/src/components/layout/pane/footer/model.ts +11 -5
- package/src/components/layout/pane/header.tsx +10 -3
- package/src/components/layout/pane/index.tsx +1 -0
- package/src/components/layout/pane/pane-tabs.tsx +9 -1
- package/src/components/layout/shell/chrome.ts +19 -6
- package/src/components/layout/shell/index.tsx +2 -1
- package/src/components/layout/shell/pane/layers.tsx +19 -1
- package/src/components/layout/status-bar.tsx +2 -2
- package/src/components/market-board/index.tsx +11 -3
- package/src/components/onboarding/onboarding-wizard.tsx +1 -0
- package/src/components/onboarding/portfolio-step/broker-setup-panel.tsx +2 -2
- package/src/components/onboarding/wizard-broker-sync.ts +4 -1
- package/src/components/pane-settings-dialog/desktop.tsx +20 -7
- package/src/components/pane-settings-dialog/tui.tsx +17 -9
- package/src/components/pane-settings-dialog/value.ts +8 -1
- package/src/components/pane-settings-dialog.tsx +44 -13
- package/src/components/sign-in-code-panel.tsx +27 -19
- package/src/components/ui/column-grid.tsx +48 -4
- package/src/components/ui/country-flag-art.tsx +180 -0
- package/src/components/ui/country-flag.tsx +118 -12
- package/src/components/ui/data-table/opentui/index.tsx +61 -2
- package/src/components/ui/data-table/opentui/model.ts +109 -2
- package/src/components/ui/data-table/types.ts +1 -1
- package/src/components/ui/display.tsx +5 -1
- package/src/components/ui/index.ts +3 -1
- package/src/components/ui/logo-mark.tsx +11 -2
- package/src/components/ui/query-bar.tsx +1 -1
- package/src/components/ui/row-notes.ts +79 -0
- package/src/components/ui/stat-grid.tsx +28 -3
- package/src/components/ui/status.tsx +3 -1
- package/src/core/app-services.ts +4 -0
- package/src/core/state/app/layout.ts +4 -4
- package/src/data/cached-query.ts +8 -1
- package/src/data/config/chart-settings.ts +3 -3
- package/src/data/config/home.ts +10 -2
- package/src/data/config/layout.ts +4 -1
- package/src/data/config/store/node.ts +4 -0
- package/src/data/config/store/normalize.ts +13 -3
- package/src/data/config/store/portfolio-as-of-column.ts +2 -2
- package/src/data/json-storage.ts +2 -0
- package/src/data/saved-copies.ts +84 -0
- package/src/docs/snapshot.json +65 -32
- package/src/i18n/es.ts +51 -12
- package/src/i18n/ja.ts +51 -12
- package/src/i18n/ko.ts +51 -12
- package/src/i18n/zh-cn.ts +51 -12
- package/src/i18n/zh-tw.ts +51 -12
- package/src/layout/desks.ts +1 -1
- package/src/layout/launch-layout.ts +1 -1
- package/src/layout/pane-manager/floating-actions.ts +5 -3
- package/src/layout/pane-manager/floating.ts +43 -1
- package/src/layout/pane-manager/index.ts +2 -0
- package/src/layout/selected-ticker.ts +74 -0
- package/src/market-data/depositary-pair.ts +251 -0
- package/src/market-data/futures-board.ts +1 -1
- package/src/market-data/futures-contract.ts +124 -40
- package/src/market-data/fx-closes.ts +17 -2
- package/src/market-data/hooks.tsx +19 -11
- package/src/market-data/market/change-basis.ts +49 -7
- package/src/market-data/market/freshness.ts +34 -5
- package/src/market-data/market/period-return.ts +163 -0
- package/src/market-data/market/trading-sessions.ts +13 -0
- package/src/market-data/market/year-to-date.ts +8 -13
- package/src/market-data/performance.ts +20 -14
- package/src/market-data/perpetual-premium.ts +32 -0
- package/src/market-data/published-apac-sessions.ts +2 -1
- package/src/market-data/published-futures-sessions.ts +69 -0
- package/src/market-data/quotes/contributions.ts +5 -1
- package/src/market-data/quotes/freshness.ts +42 -0
- package/src/market-data/quotes/intraday-bar.ts +37 -0
- package/src/market-data/quotes/regular-session-valuation.ts +13 -8
- package/src/market-data/quotes/resolution.ts +4 -2
- package/src/market-data/tax-equivalent.ts +1 -1
- package/src/market-data/ticker-price-returns.ts +3 -1
- package/src/news/aggregator.ts +5 -1
- package/src/news/news-model.ts +4 -0
- package/src/news/types.ts +11 -0
- package/src/notifications/app-notifier.ts +1 -1
- package/src/plugins/auto-update.ts +2 -2
- package/src/plugins/builtin/account-management/index.tsx +1 -0
- package/src/plugins/builtin/account-management/pane.tsx +9 -8
- package/src/plugins/builtin/alerts/alert-engine.ts +30 -18
- package/src/plugins/builtin/alerts/calendar-events.ts +378 -0
- package/src/plugins/builtin/alerts/cli.ts +485 -76
- package/src/plugins/builtin/alerts/command.ts +5 -10
- package/src/plugins/builtin/alerts/event-rows.ts +9 -5
- package/src/plugins/builtin/alerts/events-pane.tsx +71 -56
- package/src/plugins/builtin/alerts/events.ts +108 -5
- package/src/plugins/builtin/alerts/fired-log.ts +78 -0
- package/src/plugins/builtin/alerts/format.ts +2 -1
- package/src/plugins/builtin/alerts/headless.ts +100 -39
- package/src/plugins/builtin/alerts/history-pane.tsx +105 -62
- package/src/plugins/builtin/alerts/history-rows.ts +89 -0
- package/src/plugins/builtin/alerts/index.tsx +45 -18
- package/src/plugins/builtin/alerts/iv-level.ts +365 -0
- package/src/plugins/builtin/alerts/levels.ts +3 -3
- package/src/plugins/builtin/alerts/pane.tsx +97 -29
- package/src/plugins/builtin/alerts/price.ts +35 -0
- package/src/plugins/builtin/alerts/quotes.ts +24 -0
- package/src/plugins/builtin/alerts/research-builder.ts +84 -11
- package/src/plugins/builtin/alerts/research-rules.ts +77 -3
- package/src/plugins/builtin/alerts/scheduled-check.ts +206 -32
- package/src/plugins/builtin/alerts/scheduled-sources.ts +26 -3
- package/src/plugins/builtin/alerts/scheduled.ts +188 -29
- package/src/plugins/builtin/alerts/storage.ts +13 -10
- package/src/plugins/builtin/alerts/targets.ts +12 -3
- package/src/plugins/builtin/analytics/index.tsx +8 -2
- package/src/plugins/builtin/analytics/metrics.ts +1 -1
- package/src/plugins/builtin/analytics/risk-book.ts +215 -0
- package/src/plugins/builtin/analytics/risk-client.ts +13 -6
- package/src/plugins/builtin/analytics/risk-headless.ts +55 -21
- package/src/plugins/builtin/analytics/risk-math.ts +6 -3
- package/src/plugins/builtin/analytics/risk-model.ts +297 -104
- package/src/plugins/builtin/analytics/risk-options.ts +17 -2
- package/src/plugins/builtin/analytics/risk-pane.tsx +107 -43
- package/src/plugins/builtin/attention/pane.tsx +22 -16
- package/src/plugins/builtin/awards/headless.ts +7 -3
- package/src/plugins/builtin/awards/model.ts +18 -0
- package/src/plugins/builtin/awards/pane.tsx +12 -9
- package/src/plugins/builtin/backtest/export.ts +1 -1
- package/src/plugins/builtin/backtest/headless.ts +3 -3
- package/src/plugins/builtin/backtest/rules.ts +41 -5
- package/src/plugins/builtin/broker-manager/add-flow.tsx +12 -7
- package/src/plugins/builtin/broker-manager/detail.tsx +47 -19
- package/src/plugins/builtin/broker-manager/footer.ts +27 -11
- package/src/plugins/builtin/broker-manager/index.tsx +21 -12
- package/src/plugins/builtin/broker-manager/keyboard.ts +1 -1
- package/src/plugins/builtin/broker-manager/model.ts +12 -2
- package/src/plugins/builtin/broker-manager/pane-actions.tsx +183 -57
- package/src/plugins/builtin/broker-manager/table.ts +28 -12
- package/src/plugins/builtin/broker-trading/account-picker.tsx +2 -1
- package/src/plugins/builtin/broker-trading/chart-levels.ts +82 -13
- package/src/plugins/builtin/broker-trading/controller.ts +45 -13
- package/src/plugins/builtin/broker-trading/dock.tsx +24 -4
- package/src/plugins/builtin/broker-trading/headless.ts +2 -1
- package/src/plugins/builtin/broker-trading/index.tsx +7 -1
- package/src/plugins/builtin/broker-trading/linked-orders.ts +148 -0
- package/src/plugins/builtin/broker-trading/order-feed.ts +75 -7
- package/src/plugins/builtin/broker-trading/orders.tsx +109 -31
- package/src/plugins/builtin/broker-trading/overview-orders.tsx +9 -3
- package/src/plugins/builtin/broker-trading/pane-model.ts +30 -2
- package/src/plugins/builtin/broker-trading/pane.tsx +115 -26
- package/src/plugins/builtin/broker-trading/ticket-parts.tsx +36 -7
- package/src/plugins/builtin/broker-trading/ticket.tsx +122 -36
- package/src/plugins/builtin/buildout/cells.tsx +4 -0
- package/src/plugins/builtin/buildout/detail/index.tsx +5 -1
- package/src/plugins/builtin/buildout/detail/ui.tsx +7 -4
- package/src/plugins/builtin/buildout/pane/index.tsx +34 -18
- package/src/plugins/builtin/buildout/pane/status.tsx +0 -4
- package/src/plugins/builtin/builtin-plugin-meta.ts +1 -1
- package/src/plugins/builtin/catalysts/client.ts +2 -2
- package/src/plugins/builtin/catalysts/detail.tsx +3 -2
- package/src/plugins/builtin/catalysts/index.tsx +1 -1
- package/src/plugins/builtin/catalysts/model.ts +49 -4
- package/src/plugins/builtin/catalysts/pane.tsx +9 -11
- package/src/plugins/builtin/central-bank-rates/client.ts +5 -0
- package/src/plugins/builtin/central-bank-rates/headless.ts +36 -10
- package/src/plugins/builtin/central-bank-rates/model.ts +33 -8
- package/src/plugins/builtin/changelog/index.tsx +1 -0
- package/src/plugins/builtin/chart-composer/catalog-inventory.ts +1 -0
- package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +2 -1
- package/src/plugins/builtin/chart-composer/chart-spec.ts +7 -0
- package/src/plugins/builtin/chart-composer/cli-options.ts +2 -5
- package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +2 -1
- package/src/plugins/builtin/chart-composer/editor/controller.ts +2 -0
- package/src/plugins/builtin/chart-composer/editor.tsx +4 -1
- package/src/plugins/builtin/chart-composer/headless-schema.ts +28 -26
- package/src/plugins/builtin/chart-composer/headless.ts +253 -35
- package/src/plugins/builtin/chart-composer/index.tsx +12 -2
- package/src/plugins/builtin/chart-composer/leverage-overlay.ts +142 -0
- package/src/plugins/builtin/chart-composer/pane.tsx +128 -28
- package/src/plugins/builtin/chart-composer/series-catalog.ts +1 -0
- package/src/plugins/builtin/chart-composer/series-expression.ts +65 -6
- package/src/plugins/builtin/chart-composer/session-history.ts +15 -21
- package/src/plugins/builtin/chart-composer/session-range.ts +4 -2
- package/src/plugins/builtin/chart-composer/settings.ts +31 -19
- package/src/plugins/builtin/chart-composer/use-series-catalog.ts +5 -6
- package/src/plugins/builtin/chart-composer/viewport-labels.ts +18 -8
- package/src/plugins/builtin/chat/attachments/model.ts +3 -1
- package/src/plugins/builtin/chat/content/index.tsx +1 -1
- package/src/plugins/builtin/chat/pane-links/open.ts +1 -1
- package/src/plugins/builtin/chat/people.ts +1 -1
- package/src/plugins/builtin/clinical-trials/client.ts +5 -2
- package/src/plugins/builtin/clinical-trials/model.ts +13 -4
- package/src/plugins/builtin/clinical-trials/pane.tsx +32 -12
- package/src/plugins/builtin/clinical-trials/ticker-sponsor.ts +17 -0
- package/src/plugins/builtin/cloud/askg/controller.ts +1 -1
- package/src/plugins/builtin/cloud/askg/lock-note.ts +1 -1
- package/src/plugins/builtin/cloud/askg/tool-display.ts +1 -1
- package/src/plugins/builtin/cloud/auth-commands.ts +3 -3
- package/src/plugins/builtin/cloud/team/pane-sections.tsx +105 -47
- package/src/plugins/builtin/cloud/team/pane-ui.tsx +42 -4
- package/src/plugins/builtin/cloud/team/pane.tsx +204 -64
- package/src/plugins/builtin/cloud/thesis/store.ts +45 -22
- package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
- package/src/plugins/builtin/commodities-energy/index.tsx +29 -2
- package/src/plugins/builtin/commodities-energy/view-state.ts +2 -0
- package/src/plugins/builtin/commodity-balances/pane.tsx +14 -8
- package/src/plugins/builtin/company-attention/app-rank.tsx +11 -10
- package/src/plugins/builtin/company-attention/building-model.ts +222 -0
- package/src/plugins/builtin/company-attention/building.tsx +172 -0
- package/src/plugins/builtin/company-attention/client.ts +117 -1
- package/src/plugins/builtin/company-attention/evidence.ts +16 -3
- package/src/plugins/builtin/company-attention/headless.ts +101 -5
- package/src/plugins/builtin/company-attention/index.tsx +6 -3
- package/src/plugins/builtin/company-attention/model.ts +33 -7
- package/src/plugins/builtin/company-attention/moves-model.ts +253 -0
- package/src/plugins/builtin/company-attention/moves.tsx +159 -0
- package/src/plugins/builtin/company-attention/pane.tsx +89 -31
- package/src/plugins/builtin/company-attention/signals-model.ts +229 -0
- package/src/plugins/builtin/company-attention/signals.tsx +160 -0
- package/src/plugins/builtin/company-kpis/headless.ts +3 -2
- package/src/plugins/builtin/company-kpis/model.ts +2 -2
- package/src/plugins/builtin/company-kpis/pane.tsx +5 -4
- package/src/plugins/builtin/composite-plugins.ts +2 -1
- package/src/plugins/builtin/congress-trades/headless.ts +1 -1
- package/src/plugins/builtin/connections/index.ts +1 -0
- package/src/plugins/builtin/correlation/headless-schema.ts +3 -2
- package/src/plugins/builtin/correlation/headless.ts +7 -4
- package/src/plugins/builtin/correlation/relationship/model.ts +1 -0
- package/src/plugins/builtin/correlation/settings.ts +1 -0
- package/src/plugins/builtin/cot/headless.ts +28 -6
- package/src/plugins/builtin/cot/model.ts +12 -0
- package/src/plugins/builtin/cot/pane.tsx +7 -5
- package/src/plugins/builtin/cpi/headless.ts +5 -1
- package/src/plugins/builtin/cpi/pane.tsx +11 -9
- package/src/plugins/builtin/credit-boards/model.ts +2 -0
- package/src/plugins/builtin/credit-documents/headless.ts +1 -1
- package/src/plugins/builtin/credit-documents/pane.tsx +8 -7
- package/src/plugins/builtin/crypto-board/client.ts +86 -0
- package/src/plugins/builtin/crypto-board/defi-view.tsx +218 -0
- package/src/plugins/builtin/crypto-board/defi.ts +239 -0
- package/src/plugins/builtin/crypto-board/headless.ts +117 -6
- package/src/plugins/builtin/crypto-board/index.tsx +8 -3
- package/src/plugins/builtin/crypto-board/model.ts +40 -8
- package/src/plugins/builtin/crypto-board/pane.tsx +55 -21
- package/src/plugins/builtin/crypto-board/series.ts +19 -1
- package/src/plugins/builtin/crypto-etf-flows/client.ts +60 -0
- package/src/plugins/builtin/crypto-etf-flows/headless.ts +132 -0
- package/src/plugins/builtin/crypto-etf-flows/index.tsx +44 -0
- package/src/plugins/builtin/crypto-etf-flows/model.ts +121 -0
- package/src/plugins/builtin/crypto-etf-flows/pane.tsx +193 -0
- package/src/plugins/builtin/debt-maturities/pane.tsx +4 -3
- package/src/plugins/builtin/debug/index.tsx +1 -0
- package/src/plugins/builtin/dividend-yield/index.tsx +1 -1
- package/src/plugins/builtin/docs/index.tsx +1 -1
- package/src/plugins/builtin/docs/pane.tsx +2 -2
- package/src/plugins/builtin/docs/targets.ts +1 -1
- package/src/plugins/builtin/doe/client.ts +5 -1
- package/src/plugins/builtin/doe/headless.ts +12 -6
- package/src/plugins/builtin/doe/model.ts +43 -6
- package/src/plugins/builtin/doe/pane.tsx +19 -12
- package/src/plugins/builtin/earnings/board-model.ts +13 -6
- package/src/plugins/builtin/earnings/board-table.ts +4 -1
- package/src/plugins/builtin/earnings/board.tsx +253 -50
- package/src/plugins/builtin/earnings/calendar-model.ts +188 -0
- package/src/plugins/builtin/earnings/calendar.tsx +338 -0
- package/src/plugins/builtin/earnings/client.ts +4 -3
- package/src/plugins/builtin/earnings/headless.ts +53 -15
- package/src/plugins/builtin/earnings/history-model.ts +53 -36
- package/src/plugins/builtin/earnings/index.tsx +15 -22
- package/src/plugins/builtin/earnings/model.ts +17 -12
- package/src/plugins/builtin/earnings/scope.ts +89 -0
- package/src/plugins/builtin/earnings-calls/calendar.tsx +310 -0
- package/src/plugins/builtin/earnings-calls/data.ts +146 -2
- package/src/plugins/builtin/earnings-calls/headless.ts +151 -9
- package/src/plugins/builtin/earnings-calls/index.tsx +3 -3
- package/src/plugins/builtin/earnings-calls/lock-note.ts +1 -1
- package/src/plugins/builtin/earnings-calls/pane.tsx +149 -31
- package/src/plugins/builtin/earnings-calls/upcoming.ts +195 -0
- package/src/plugins/builtin/earnings-ripple/pane.tsx +10 -5
- package/src/plugins/builtin/econ/calendar-model.ts +132 -20
- package/src/plugins/builtin/econ/detail-view.tsx +48 -10
- package/src/plugins/builtin/econ/fred-catalog.ts +23 -6
- package/src/plugins/builtin/econ/fred-series-map.ts +4 -0
- package/src/plugins/builtin/econ/index.tsx +112 -25
- package/src/plugins/builtin/econ/print-watch.ts +2 -1
- package/src/plugins/builtin/econ/types.ts +32 -1
- package/src/plugins/builtin/econ-statistics/client.ts +16 -3
- package/src/plugins/builtin/econ-statistics/defs.ts +4 -0
- package/src/plugins/builtin/econ-statistics/detail.tsx +2 -2
- package/src/plugins/builtin/econ-statistics/headless.ts +13 -2
- package/src/plugins/builtin/econ-statistics/index.tsx +3 -3
- package/src/plugins/builtin/econ-statistics/pane.tsx +2 -1
- package/src/plugins/builtin/econ-statistics/stats.ts +103 -0
- package/src/plugins/builtin/econ-statistics/view.ts +16 -1
- package/src/plugins/builtin/equity-screener/client.ts +21 -3
- package/src/plugins/builtin/equity-screener/headless.ts +77 -5
- package/src/plugins/builtin/equity-screener/live.ts +1 -1
- package/src/plugins/builtin/equity-screener/model.ts +34 -0
- package/src/plugins/builtin/equity-screener/pane.tsx +148 -106
- package/src/plugins/builtin/equity-screener/screen-check.ts +90 -0
- package/src/plugins/builtin/equity-screener/ticker-check.tsx +148 -0
- package/src/plugins/builtin/estimate-revisions/headless.ts +3 -1
- package/src/plugins/builtin/estimate-revisions/lock-note.ts +3 -3
- package/src/plugins/builtin/estimate-revisions/model.ts +8 -10
- package/src/plugins/builtin/exposure/headless.ts +51 -6
- package/src/plugins/builtin/exposure/index.tsx +28 -2
- package/src/plugins/builtin/exposure/model.ts +7 -0
- package/src/plugins/builtin/exposure/pane.tsx +16 -10
- package/src/plugins/builtin/fear-greed/index.tsx +1 -1
- package/src/plugins/builtin/filing-events/index.tsx +1 -1
- package/src/plugins/builtin/futures/model.ts +10 -9
- package/src/plugins/builtin/futures/returns.ts +8 -36
- package/src/plugins/builtin/futures/table.tsx +1 -1
- package/src/plugins/builtin/futures-curve/client.ts +40 -9
- package/src/plugins/builtin/futures-curve/headless.ts +39 -17
- package/src/plugins/builtin/futures-curve/model.ts +258 -69
- package/src/plugins/builtin/futures-curve/pane.tsx +46 -17
- package/src/plugins/builtin/fx-matrix/client.ts +15 -8
- package/src/plugins/builtin/fx-matrix/headless.ts +32 -14
- package/src/plugins/builtin/fx-matrix/index.tsx +13 -11
- package/src/plugins/builtin/fx-matrix/live-legs.ts +22 -0
- package/src/plugins/builtin/fx-matrix/settings.ts +2 -1
- package/src/plugins/builtin/gpu/board.tsx +4 -1
- package/src/plugins/builtin/gpu/changes.tsx +10 -10
- package/src/plugins/builtin/gpu/equities.tsx +4 -1
- package/src/plugins/builtin/gpu/headless.ts +9 -4
- package/src/plugins/builtin/gpu/history.tsx +4 -2
- package/src/plugins/builtin/gpu/pane.tsx +5 -3
- package/src/plugins/builtin/help/index.tsx +13 -3
- package/src/plugins/builtin/holders/beneficial-model.ts +8 -11
- package/src/plugins/builtin/holders/beneficial-report.ts +6 -5
- package/src/plugins/builtin/holders/beneficial-view.tsx +7 -3
- package/src/plugins/builtin/holders/client.ts +15 -2
- package/src/plugins/builtin/holders/format.ts +28 -17
- package/src/plugins/builtin/holders/headless.ts +48 -8
- package/src/plugins/builtin/holders/index-holders.ts +264 -0
- package/src/plugins/builtin/holders/pane.tsx +79 -15
- package/src/plugins/builtin/holders/report-rows.ts +35 -7
- package/src/plugins/builtin/holders/table-model.ts +2 -1
- package/src/plugins/builtin/holders/thirteenf-match.ts +3 -1
- package/src/plugins/builtin/holders/treemap.tsx +2 -2
- package/src/plugins/builtin/insider/base-values.ts +11 -7
- package/src/plugins/builtin/insider/client.ts +3 -0
- package/src/plugins/builtin/insider/headless.ts +20 -7
- package/src/plugins/builtin/insider/index.tsx +17 -8
- package/src/plugins/builtin/insider/issuer.ts +34 -4
- package/src/plugins/builtin/insider/signals-client.ts +3 -3
- package/src/plugins/builtin/insider/signals.tsx +1 -1
- package/src/plugins/builtin/insider/table-model.ts +35 -13
- package/src/plugins/builtin/insider/table.tsx +5 -2
- package/src/plugins/builtin/ipo-calendar/pane.tsx +7 -4
- package/src/plugins/builtin/iv-history/client.ts +20 -0
- package/src/plugins/builtin/iv-history/events.ts +145 -0
- package/src/plugins/builtin/iv-history/format.ts +3 -0
- package/src/plugins/builtin/iv-history/headless.ts +91 -7
- package/src/plugins/builtin/iv-history/index.tsx +1 -1
- package/src/plugins/builtin/iv-history/model.ts +13 -4
- package/src/plugins/builtin/iv-history/series.ts +3 -1
- package/src/plugins/builtin/jobs/lock-note.ts +1 -1
- package/src/plugins/builtin/jobs/model.ts +4 -15
- package/src/plugins/builtin/jobs/pane.tsx +7 -5
- package/src/plugins/builtin/jobs/share-bars.tsx +11 -5
- package/src/plugins/builtin/jodi/pane.tsx +14 -8
- package/src/plugins/builtin/layout-manager/index.tsx +1 -0
- package/src/plugins/builtin/macro-day/headless.ts +20 -7
- package/src/plugins/builtin/macro-day/index.tsx +3 -2
- package/src/plugins/builtin/macro-day/model.ts +29 -8
- package/src/plugins/builtin/macro-day/pane.tsx +46 -10
- package/src/plugins/builtin/macro-day/releases.ts +55 -13
- package/src/plugins/builtin/market-heatmap/data.ts +9 -2
- package/src/plugins/builtin/market-heatmap/evidence.ts +1 -1
- package/src/plugins/builtin/market-heatmap/headless.ts +9 -6
- package/src/plugins/builtin/market-heatmap/index.tsx +3 -3
- package/src/plugins/builtin/market-heatmap/model.ts +10 -7
- package/src/plugins/builtin/market-movers/client.ts +36 -21
- package/src/plugins/builtin/market-movers/headless.ts +8 -2
- package/src/plugins/builtin/market-movers/index.tsx +16 -10
- package/src/plugins/builtin/market-movers/screener.ts +33 -11
- package/src/plugins/builtin/market-movers/session-body.tsx +4 -2
- package/src/plugins/builtin/market-movers/session-table.ts +4 -2
- package/src/plugins/builtin/market-movers/table.ts +4 -1
- package/src/plugins/builtin/market-valuation/headless.ts +2 -0
- package/src/plugins/builtin/market-valuation/view.ts +5 -0
- package/src/plugins/builtin/members/headless.ts +6 -5
- package/src/plugins/builtin/members/pane.tsx +11 -4
- package/src/plugins/builtin/mna/client.ts +1 -0
- package/src/plugins/builtin/mna/detail.tsx +20 -32
- package/src/plugins/builtin/mna/distress/detail.tsx +16 -4
- package/src/plugins/builtin/mna/distress/model.ts +3 -2
- package/src/plugins/builtin/mna/distress/pane.tsx +7 -4
- package/src/plugins/builtin/mna/headless.ts +6 -13
- package/src/plugins/builtin/mna/model.ts +93 -15
- package/src/plugins/builtin/mna/pane.tsx +5 -4
- package/src/plugins/builtin/news/headless.ts +12 -6
- package/src/plugins/builtin/news/index.tsx +10 -1
- package/src/plugins/builtin/news/wire/index.tsx +3 -2
- package/src/plugins/builtin/news/wire/news/command-bar-search.ts +26 -10
- package/src/plugins/builtin/news/wire/news/query-presets.ts +6 -2
- package/src/plugins/builtin/news/wire/rss/cli.ts +3 -3
- package/src/plugins/builtin/notes/cli.ts +50 -15
- package/src/plugins/builtin/notes/export.ts +17 -6
- package/src/plugins/builtin/notes/files.ts +16 -5
- package/src/plugins/builtin/openfda/pane.tsx +1 -1
- package/src/plugins/builtin/options/carry.ts +2 -2
- package/src/plugins/builtin/options/enrichment-model.ts +10 -9
- package/src/plugins/builtin/options/index.tsx +1 -1
- package/src/plugins/builtin/options/model-spot.ts +70 -4
- package/src/plugins/builtin/options/view.tsx +51 -23
- package/src/plugins/builtin/options-calculator/headless.ts +46 -7
- package/src/plugins/builtin/options-calculator/pane.tsx +3 -2
- package/src/plugins/builtin/options-positioning/headless.ts +11 -3
- package/src/plugins/builtin/options-positioning/model.ts +24 -0
- package/src/plugins/builtin/options-positioning/pane.tsx +10 -12
- package/src/plugins/builtin/options-scenario/client.ts +142 -29
- package/src/plugins/builtin/options-scenario/collar.ts +8 -6
- package/src/plugins/builtin/options-scenario/csp-screen-headless.ts +127 -0
- package/src/plugins/builtin/options-scenario/csp-screen-pane.tsx +165 -0
- package/src/plugins/builtin/options-scenario/csp-screen.ts +258 -0
- package/src/plugins/builtin/options-scenario/csp.ts +101 -21
- package/src/plugins/builtin/options-scenario/headless.ts +49 -21
- package/src/plugins/builtin/options-scenario/hedge.ts +20 -14
- package/src/plugins/builtin/options-scenario/index.tsx +28 -3
- package/src/plugins/builtin/options-scenario/model.ts +13 -0
- package/src/plugins/builtin/options-scenario/pane.tsx +22 -10
- package/src/plugins/builtin/perps/equity-row.tsx +11 -3
- package/src/plugins/builtin/perps/freshness.ts +8 -5
- package/src/plugins/builtin/perps/headless.ts +3 -1
- package/src/plugins/builtin/perps/list-perpetuals.ts +25 -4
- package/src/plugins/builtin/perps/live-rows.ts +161 -0
- package/src/plugins/builtin/perps/markets-section.tsx +154 -0
- package/src/plugins/builtin/perps/pane.tsx +36 -17
- package/src/plugins/builtin/perps/venue-markets.ts +96 -0
- package/src/plugins/builtin/plugin-marketplace/index.tsx +2 -1
- package/src/plugins/builtin/plugin-marketplace/pane.tsx +145 -60
- package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +78 -27
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +158 -141
- package/src/plugins/builtin/portfolio-list/cli/render.ts +49 -20
- package/src/plugins/builtin/portfolio-list/cli/shared.ts +3 -3
- package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +29 -24
- package/src/plugins/builtin/portfolio-list/headless.ts +6 -3
- package/src/plugins/builtin/portfolio-list/income.ts +13 -2
- package/src/plugins/builtin/portfolio-list/index.tsx +9 -2
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +21 -8
- package/src/plugins/builtin/portfolio-list/pane/purchase-date-fx.ts +46 -0
- package/src/plugins/builtin/portfolio-list/summary/live-accounts.ts +16 -9
- package/src/plugins/builtin/portfolio-list/summary/totals.ts +2 -15
- package/src/plugins/builtin/power/client.ts +6 -3
- package/src/plugins/builtin/power/evidence.ts +22 -7
- package/src/plugins/builtin/power/gas.tsx +5 -1
- package/src/plugins/builtin/power/pane.tsx +44 -32
- package/src/plugins/builtin/power/prices.tsx +10 -3
- package/src/plugins/builtin/research/analyst-headless.ts +25 -8
- package/src/plugins/builtin/research/analyst-model.ts +68 -3
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +63 -14
- package/src/plugins/builtin/research/event-model.ts +3 -1
- package/src/plugins/builtin/research/event-sources.ts +12 -4
- package/src/plugins/builtin/research/index.tsx +2 -1
- package/src/plugins/builtin/research/relative-valuation-basis.ts +58 -0
- package/src/plugins/builtin/research/relative-valuation-columns.ts +31 -2
- package/src/plugins/builtin/research/relative-valuation-currency.ts +12 -5
- package/src/plugins/builtin/research/relative-valuation-headless.ts +84 -26
- package/src/plugins/builtin/research/relative-valuation-model.ts +88 -19
- package/src/plugins/builtin/research/relative-valuation-pane.tsx +76 -9
- package/src/plugins/builtin/research/relative-valuation-peers.ts +1 -1
- package/src/plugins/builtin/reverse-dcf/client.ts +2 -1
- package/src/plugins/builtin/reverse-dcf/model.ts +10 -5
- package/src/plugins/builtin/risk-factors/index.tsx +2 -2
- package/src/plugins/builtin/scanner/lock-note.ts +1 -1
- package/src/plugins/builtin/seasonality/client.ts +2 -1
- package/src/plugins/builtin/sec/forms.ts +13 -0
- package/src/plugins/builtin/sec/fund-abroad.ts +32 -0
- package/src/plugins/builtin/sec/fund-facts.ts +68 -8
- package/src/plugins/builtin/sec/headless.ts +85 -8
- package/src/plugins/builtin/sec/index.tsx +58 -12
- package/src/plugins/builtin/sectors/client.ts +6 -4
- package/src/plugins/builtin/sectors/sector-model.ts +11 -15
- package/src/plugins/builtin/series-inventory.ts +2 -0
- package/src/plugins/builtin/shared/broker-reconnect.ts +107 -22
- package/src/plugins/builtin/shared/cloud-resource.ts +15 -2
- package/src/plugins/builtin/shared/cloud-upgrade.ts +34 -6
- package/src/plugins/builtin/shared/earnings-calendar.ts +375 -0
- package/src/plugins/builtin/{earnings/estimate-basis.ts → shared/earnings-estimate-basis.ts} +1 -1
- package/src/plugins/builtin/shared/earnings-report.ts +3 -3
- package/src/plugins/builtin/shared/fx-rate-freshness.ts +23 -1
- package/src/plugins/builtin/shared/job-posting.ts +129 -0
- package/src/plugins/builtin/shared/pro-lock-note.ts +3 -3
- package/src/plugins/builtin/shared/report-freshness.ts +3 -0
- package/src/plugins/builtin/shared/research-trading.tsx +23 -0
- package/src/plugins/builtin/shared/series-cache.ts +2 -0
- package/src/plugins/builtin/shared/series-list-detail.tsx +3 -1
- package/src/plugins/builtin/shared/ticker-surface.ts +2 -1
- package/src/plugins/builtin/shared/volatility/options.ts +2 -1
- package/src/plugins/builtin/short-interest/client.ts +2 -0
- package/src/plugins/builtin/short-interest/headless.ts +41 -12
- package/src/plugins/builtin/short-interest/index.tsx +23 -1
- package/src/plugins/builtin/short-interest/model.ts +70 -19
- package/src/plugins/builtin/short-interest/pane.tsx +19 -2
- package/src/plugins/builtin/short-interest/publications-client.ts +82 -0
- package/src/plugins/builtin/short-interest/publications-headless.ts +29 -0
- package/src/plugins/builtin/short-interest/publications-model.ts +50 -0
- package/src/plugins/builtin/short-interest/publications-pane.tsx +66 -0
- package/src/plugins/builtin/short-interest/schedule.ts +35 -2
- package/src/plugins/builtin/short-interest/surface.tsx +11 -4
- package/src/plugins/builtin/short-interest/types.ts +9 -0
- package/src/plugins/builtin/short-interest/watch-client.ts +14 -8
- package/src/plugins/builtin/short-interest/watch-model.ts +12 -25
- package/src/plugins/builtin/short-interest/watch-pane.tsx +5 -1
- package/src/plugins/builtin/social-mentions/client.ts +2 -1
- package/src/plugins/builtin/supply-chain/flow.tsx +33 -9
- package/src/plugins/builtin/supply-chain/model.ts +51 -3
- package/src/plugins/builtin/supply-chain/pane.tsx +78 -39
- package/src/plugins/builtin/supply-chain/row-evidence.tsx +1 -1
- package/src/plugins/builtin/themes/headless.ts +8 -5
- package/src/plugins/builtin/themes/model.ts +14 -4
- package/src/plugins/builtin/themes/pane.tsx +24 -5
- package/src/plugins/builtin/thirteenf/headless.ts +5 -5
- package/src/plugins/builtin/thirteenf/signals.ts +3 -1
- package/src/plugins/builtin/ticker-detail/adr-pair/headless.ts +123 -0
- package/src/plugins/builtin/ticker-detail/adr-pair/model.ts +132 -0
- package/src/plugins/builtin/ticker-detail/adr-pair/tab.tsx +87 -0
- package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +40 -26
- package/src/plugins/builtin/ticker-detail/data-panes/history-bars.ts +8 -4
- package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +67 -3
- package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +112 -5
- package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +17 -2
- package/src/plugins/builtin/ticker-detail/financials/aggregation.ts +21 -7
- package/src/plugins/builtin/ticker-detail/financials/model.ts +36 -1
- package/src/plugins/builtin/ticker-detail/financials/offerings.ts +56 -0
- package/src/plugins/builtin/ticker-detail/financials/ratios.ts +62 -13
- package/src/plugins/builtin/ticker-detail/financials/tab.tsx +30 -4
- package/src/plugins/builtin/ticker-detail/headless-schema.ts +14 -2
- package/src/plugins/builtin/ticker-detail/headless.ts +148 -35
- package/src/plugins/builtin/ticker-detail/index.tsx +37 -5
- package/src/plugins/builtin/ticker-detail/overview/model.ts +65 -10
- package/src/plugins/builtin/ticker-detail/overview/pane.tsx +9 -1
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +68 -11
- package/src/plugins/builtin/ticker-detail/pane.tsx +11 -0
- package/src/plugins/builtin/ticker-detail/quote-footer.ts +8 -3
- package/src/plugins/builtin/ticker-detail/research-tabs.ts +11 -0
- package/src/plugins/builtin/vol-surface/client.ts +28 -7
- package/src/plugins/builtin/vol-surface/headless.ts +43 -15
- package/src/plugins/builtin/vol-surface/model.ts +34 -12
- package/src/plugins/builtin/vol-surface/pane.tsx +33 -13
- package/src/plugins/builtin/vol-surface/stored.ts +34 -3
- package/src/plugins/builtin/vol-surface/tables.ts +14 -0
- package/src/plugins/builtin/volatility/model.ts +5 -10
- package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +4 -3
- package/src/plugins/builtin/world-venue-map/basemap.ts +3 -1
- package/src/plugins/builtin/world-venue-map/chokepoint-chart.ts +40 -0
- package/src/plugins/builtin/world-venue-map/evidence.ts +1 -1
- package/src/plugins/builtin/world-venue-map/geo-series.ts +90 -11
- package/src/plugins/builtin/world-venue-map/headless.ts +1 -1
- package/src/plugins/builtin/world-venue-map/index.ts +3 -26
- package/src/plugins/builtin/world-venue-map/layers.ts +1 -1
- package/src/plugins/builtin/world-venue-map/map.tsx +2 -1
- package/src/plugins/builtin/world-venue-map/pane.tsx +4 -2
- package/src/plugins/builtin/world-venue-map/venue-header.tsx +15 -4
- package/src/plugins/builtin/yield-curve/client.ts +25 -0
- package/src/plugins/builtin/yield-curve/curves.ts +7 -4
- package/src/plugins/builtin/yield-curve/headless.ts +38 -4
- package/src/plugins/builtin/yield-curve/history.ts +4 -3
- package/src/plugins/builtin/yield-curve/index.tsx +12 -6
- package/src/plugins/builtin/yield-curve/swaps-model.ts +93 -0
- package/src/plugins/builtin/yield-curve/swaps.tsx +99 -0
- package/src/plugins/bundle.ts +1 -1
- package/src/plugins/catalog-browser.ts +2 -1
- package/src/plugins/compat.ts +3 -3
- package/src/plugins/dependencies.ts +75 -14
- package/src/plugins/extracted-plugins.ts +132 -34
- package/src/plugins/host-link.ts +149 -34
- package/src/plugins/installer.ts +35 -10
- package/src/plugins/loader.ts +206 -38
- package/src/plugins/manager-node.ts +2 -2
- package/src/plugins/marketplace/deactivation.ts +22 -0
- package/src/plugins/marketplace/model.ts +2 -2
- package/src/plugins/marketplace/packs.ts +1 -1
- package/src/plugins/ownership.ts +1 -1
- package/src/plugins/peer-retry.ts +155 -0
- package/src/plugins/registry/contributions.ts +3 -1
- package/src/plugins/registry/index.ts +4 -3
- package/src/plugins/registry/plugin-state.ts +3 -0
- package/src/plugins/seed-notice.ts +20 -0
- package/src/plugins/shortcut-argument.ts +39 -0
- package/src/portfolio/allocation.ts +1 -1
- package/src/portfolio/collection-name.ts +31 -0
- package/src/portfolio/column-values.ts +10 -8
- package/src/portfolio/cost-fx.ts +296 -19
- package/src/portfolio/manual-lots.ts +75 -0
- package/src/portfolio/mutations.ts +60 -22
- package/src/portfolio/suffixed-listings.ts +209 -0
- package/src/portfolio/totals-currency.ts +24 -0
- package/src/public/__snapshots__/public-api.test.ts.snap +14 -0
- package/src/public/time-series.ts +11 -8
- package/src/remote/schema.ts +1 -1
- package/src/renderers/browser/config-host.ts +3 -0
- package/src/renderers/browser/main.tsx +23 -3
- package/src/renderers/dom/boot-frame-page.ts +187 -0
- package/src/renderers/dom/boot-frame.ts +237 -0
- package/src/renderers/dom/build-assets.ts +46 -8
- package/src/renderers/dom/desktop/controls.tsx +1 -1
- package/src/renderers/dom/desktop/query-bar.tsx +2 -0
- package/src/renderers/dom/dom-ui-host.tsx +4 -29
- package/src/renderers/dom/host/ascii-text.ts +16 -2
- package/src/renderers/dom/host/box.tsx +43 -2
- package/src/renderers/dom/host/chart-surface.tsx +2 -0
- package/src/renderers/dom/host/hls.chunk.ts +3 -0
- package/src/renderers/dom/host/image-surface.tsx +49 -0
- package/src/renderers/dom/host/media-surface.tsx +24 -18
- package/src/renderers/dom/host/mouse.ts +30 -0
- package/src/renderers/dom/host/size-observer.ts +1 -1
- package/src/renderers/dom/host/style.ts +1 -1
- package/src/renderers/dom/host/tabs.tsx +16 -5
- package/src/renderers/dom/host/top-surface.ts +127 -0
- package/src/renderers/dom/styles.css +115 -0
- package/src/renderers/dom/test-utils.tsx +2 -1
- package/src/renderers/electrobun/bun/application-menu/index.ts +3 -3
- package/src/renderers/electrobun/bun/core-capabilities.ts +9 -1
- package/src/renderers/electrobun/bun/desktop/backend-requests.ts +3 -0
- package/src/renderers/electrobun/bun/desktop/backend.ts +56 -3
- package/src/renderers/electrobun/bun/desktop/detached-windows.ts +1 -1
- package/src/renderers/electrobun/bun/desktop/host-requests.ts +9 -3
- package/src/renderers/electrobun/bun/desktop/initialization.ts +81 -18
- package/src/renderers/electrobun/bun/desktop/update.ts +210 -30
- package/src/renderers/electrobun/bun/external-plugins.ts +29 -7
- package/src/renderers/electrobun/bun/index.ts +11 -1
- package/src/renderers/electrobun/bun/window/boot-frame.ts +67 -0
- package/src/renderers/electrobun/bun/window/create.ts +4 -1
- package/src/renderers/electrobun/shared/boot-frame.ts +7 -0
- package/src/renderers/electrobun/shared/protocol.ts +6 -1
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -1
- package/src/renderers/electrobun/view/config-host.ts +3 -0
- package/src/renderers/electrobun/view/fatal-screen.tsx +1 -1
- package/src/renderers/electrobun/view/main.tsx +30 -4
- package/src/renderers/electrobun/view/news-source.ts +9 -7
- package/src/renderers/electrobun/view/remote/asset-data-client.ts +9 -2
- package/src/renderers/electrobun/view/ui-host.tsx +1 -1
- package/src/renderers/opentui/browser-open.ts +88 -0
- package/src/renderers/opentui/host.tsx +5 -14
- package/src/renderers/opentui/image/loader.ts +3 -2
- package/src/renderers/opentui/native-smoke.ts +10 -1
- package/src/renderers/opentui/pane-image/index.ts +2 -1
- package/src/renderers/opentui/render-lib.ts +253 -0
- package/src/renderers/opentui/render-timing-smoke.ts +1 -1
- package/src/renderers/opentui/start.tsx +8 -1
- package/src/renderers/share/layout-view.tsx +2 -2
- package/src/renderers/share/main.tsx +4 -4
- package/src/renderers/share/view.tsx +1 -1
- package/src/series/resolve.ts +22 -6
- package/src/series/standalone.ts +30 -2
- package/src/series/types.ts +8 -1
- package/src/shares/api.ts +4 -1
- package/src/shares/pane.ts +1 -1
- package/src/sources/gloomberb-cloud/fred-series.ts +46 -1
- package/src/sources/gloomberb-cloud/index.ts +39 -16
- package/src/sources/gloomberb-cloud/news.ts +39 -0
- package/src/sources/gloomberb-cloud/normalizers.ts +14 -1
- package/src/sources/gloomberb-cloud/perpetuals.ts +49 -1
- package/src/sources/listing-symbols.ts +37 -0
- package/src/sources/provider-errors.ts +16 -2
- package/src/sources/provider-router/financial-routes.ts +21 -3
- package/src/sources/provider-router/financials.ts +15 -2
- package/src/sources/provider-router/history.ts +30 -8
- package/src/sources/provider-router/index.ts +16 -0
- package/src/sources/provider-router/primary.ts +1 -1
- package/src/state/app/bootstrap.ts +23 -0
- package/src/state/hooks/inline-tickers.ts +30 -5
- package/src/sync/controller.ts +1 -1
- package/src/sync/core-contributors.ts +46 -14
- package/src/team/collections-sync.ts +2 -1
- package/src/team/collections.ts +178 -17
- package/src/telemetry/crash-reports.ts +21 -4
- package/src/telemetry/update-failures-node.ts +59 -0
- package/src/telemetry/update-failures.ts +307 -0
- package/src/test-support/builtin-panes.ts +1 -1
- package/src/theme/colors.ts +3 -30
- package/src/theme/ui-tokens.ts +37 -1
- package/src/tickers/company-name-listing.ts +215 -36
- package/src/tickers/company-name.ts +43 -0
- package/src/tickers/index-roots.ts +47 -0
- package/src/tickers/instrument-label.ts +5 -1
- package/src/tickers/listing-fate.ts +30 -0
- package/src/tickers/metadata.ts +10 -0
- package/src/tickers/perpetual-listing.ts +5 -2
- package/src/tickers/search/home-listing.ts +75 -0
- package/src/tickers/search/index.ts +76 -27
- package/src/tickers/search/ranking.ts +54 -4
- package/src/tickers/search/upsert.ts +29 -0
- package/src/tickers/terminal-codes.ts +416 -40
- package/src/time-series/bar-aggregation.ts +243 -0
- package/src/time-series/base-series.ts +307 -0
- package/src/time-series/chart-bounds.ts +349 -0
- package/src/time-series/chart-seed.ts +142 -0
- package/src/time-series/economic.ts +5 -0
- package/src/time-series/fundamentals.ts +18 -3
- package/src/time-series/history-acquisition.ts +499 -0
- package/src/time-series/leverage.ts +100 -0
- package/src/time-series/market-resolution.ts +4 -2
- package/src/time-series/market.ts +2 -1
- package/src/time-series/price-comparison.ts +175 -30
- package/src/time-series/range.ts +9 -1
- package/src/time-series/resolution.ts +174 -16
- package/src/time-series/resolve-context.ts +157 -0
- package/src/time-series/resolve.ts +126 -1577
- package/src/time-series/series-name.ts +38 -0
- package/src/time-series/series-presentation.ts +208 -0
- package/src/time-series/spec.ts +11 -6
- package/src/time-series/studies.ts +109 -12
- package/src/time-series/tail-reconcile.ts +121 -0
- package/src/time-series/types.ts +29 -2
- package/src/time-series/use-chart-resolution.ts +4 -5
- package/src/types/broker.ts +10 -0
- package/src/types/config.ts +14 -0
- package/src/types/data-provider.ts +20 -0
- package/src/types/exchange-rate.ts +6 -0
- package/src/types/financials.ts +104 -7
- package/src/types/headless.ts +83 -6
- package/src/types/instrument.ts +3 -0
- package/src/types/issuer-listings.ts +28 -0
- package/src/types/plugin.ts +65 -8
- package/src/types/price-history.ts +2 -0
- package/src/types/ticker.ts +13 -0
- package/src/types/trading.ts +59 -1
- package/src/ui/ascii-font.ts +13 -1
- package/src/ui/host.tsx +6 -1
- package/src/updater/command-names.ts +175 -0
- package/src/updater/failure.ts +163 -0
- package/src/updater/index.ts +97 -28
- package/src/utils/calendar-date.ts +32 -15
- package/src/utils/cash-runway.ts +241 -0
- package/src/utils/central-banks.ts +42 -0
- package/src/utils/cli-output.ts +259 -80
- package/src/utils/contract-month.ts +16 -0
- package/src/utils/crypto-pair.ts +61 -3
- package/src/utils/currency-pair.ts +26 -0
- package/src/utils/currency-units.ts +29 -0
- package/src/utils/datetime-format.ts +10 -0
- package/src/utils/debug-log.ts +1 -1
- package/src/utils/decimal-comma.ts +39 -6
- package/src/utils/exchange-announcements.ts +71 -0
- package/src/utils/exchange-rate-snapshot.ts +10 -0
- package/src/utils/financial-statements.ts +83 -4
- package/src/utils/format.ts +34 -16
- package/src/utils/fundamentals.ts +150 -34
- package/src/utils/fx-market-hours.ts +10 -1
- package/src/utils/latest-financial-period.ts +8 -0
- package/src/utils/linux-libc.ts +54 -0
- package/src/utils/market-capitalization.ts +111 -15
- package/src/utils/max-drawdown.ts +64 -0
- package/src/utils/network-failure.ts +83 -0
- package/src/utils/option-expiry.ts +139 -7
- package/src/utils/price-earnings.ts +11 -5
- package/src/utils/price-history.ts +18 -8
- package/src/utils/price-window.ts +131 -0
- package/src/utils/release-date.ts +47 -0
- package/src/utils/sec.ts +71 -0
- package/src/utils/throttled-fetch.ts +11 -4
- package/src/utils/trailing-eps.ts +67 -0
- package/src/utils/typed-text.ts +21 -0
- package/src/utils/utc-time.ts +24 -1
- package/src/version.ts +6 -0
- package/src/cli/pane-functions/screenshot.ts +0 -2122
|
@@ -1,27 +1,35 @@
|
|
|
1
|
-
import { useCallback, useEffect, useMemo, useRef } from "react";
|
|
1
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
2
2
|
import {
|
|
3
3
|
DataTableStackView,
|
|
4
|
+
PageStackView,
|
|
4
5
|
PaneStatusBody,
|
|
5
6
|
QueryBar,
|
|
6
7
|
usePaneFooter,
|
|
7
8
|
usePaneMenuItems,
|
|
8
9
|
usePaneStatusFooter,
|
|
9
10
|
type DataTableKeyEvent,
|
|
11
|
+
type QueryBarFilter,
|
|
12
|
+
type QueryBarView,
|
|
10
13
|
} from "../../../components";
|
|
11
|
-
import { handleRefreshKey } from "../../../components/data-table/table-pane";
|
|
14
|
+
import { handleRefreshKey, usePaneRefreshKey } from "../../../components/data-table/table-pane";
|
|
15
|
+
import { openFormModal } from "../../../components/form-modal";
|
|
16
|
+
import { FILL_REST } from "../../../components/ui/fill";
|
|
12
17
|
import type { EarningsCalendarQuery } from "../../../api-client/earnings";
|
|
13
|
-
import { useAppSelector, usePaneSettingValue } from "../../../state/app/context";
|
|
18
|
+
import { useAppSelector, usePaneAppConfig, usePaneSettingValue } from "../../../state/app/context";
|
|
14
19
|
import { useLiveStreamingSetting } from "../../../state/hooks/live-streaming";
|
|
15
20
|
import { useAsyncResource, useAutoRefresh, usePluginPaneState, useUpdatedAgo } from "../../../public/react";
|
|
16
21
|
import type { EarningsEvent } from "../../../types/data-provider";
|
|
22
|
+
import { getSharedRegistry } from "../../registry/shared";
|
|
23
|
+
import { Box, useUiCapabilities } from "../../../ui";
|
|
17
24
|
import { useAssetData, usePluginAppActions, usePluginTickerActions } from "../../runtime";
|
|
25
|
+
import { earningsResultsAlertValues } from "../alerts/research-builder";
|
|
26
|
+
import { cachedMembers, loadMembers } from "../members/client";
|
|
18
27
|
import { isBoardRowLoading, useQuoteBoard } from "../shared/use-quote-board";
|
|
19
28
|
import {
|
|
20
29
|
addDays,
|
|
21
30
|
boardReport,
|
|
22
31
|
boardRows,
|
|
23
32
|
fallbackReport,
|
|
24
|
-
marketDays,
|
|
25
33
|
newYorkToday,
|
|
26
34
|
ownershipBySymbol,
|
|
27
35
|
relativeDays,
|
|
@@ -31,9 +39,36 @@ import {
|
|
|
31
39
|
type BoardSort,
|
|
32
40
|
} from "./board-model";
|
|
33
41
|
import { boardColumns, boardHasActuals, renderBoardCell, renderBoardSection, SORTABLE, type BoardCellContext, type BoardColumn } from "./board-table";
|
|
34
|
-
import {
|
|
42
|
+
import { EarningsCalendarView, CALENDAR_GROUP_ROWS, calendarSlotsPerRow } from "./calendar";
|
|
43
|
+
import {
|
|
44
|
+
boardRangeDays,
|
|
45
|
+
boardRangeLabel,
|
|
46
|
+
boardRangeWeek,
|
|
47
|
+
boardRangeWords,
|
|
48
|
+
CALENDAR_WEEK_OFFSETS,
|
|
49
|
+
calendarDays,
|
|
50
|
+
calendarGroupKey,
|
|
51
|
+
calendarWeekDates,
|
|
52
|
+
calendarWeekLabel,
|
|
53
|
+
isBoardRangeDay,
|
|
54
|
+
requestedBoardRange,
|
|
55
|
+
type BoardRange,
|
|
56
|
+
} from "./calendar-model";
|
|
57
|
+
import { cachedEarningsCalendar, earningsCalendarKey, loadEarningsBoard } from "./client";
|
|
35
58
|
import { loadEarningsCalendar } from "./data/cache";
|
|
36
59
|
import { EarningsHistoryView } from "./history";
|
|
60
|
+
import {
|
|
61
|
+
ALL_SCOPE,
|
|
62
|
+
earningsScopeOptions,
|
|
63
|
+
MINE_SCOPE,
|
|
64
|
+
readEarningsScope,
|
|
65
|
+
SECTOR_HOLDINGS_FUND,
|
|
66
|
+
sectorSymbols,
|
|
67
|
+
type EarningsScope,
|
|
68
|
+
} from "./scope";
|
|
69
|
+
|
|
70
|
+
const NO_SYMBOLS: string[] = [];
|
|
71
|
+
const NONE_EXPANDED: ReadonlySet<string> = new Set();
|
|
37
72
|
|
|
38
73
|
/** The stored calendar reaches about three months ahead. */
|
|
39
74
|
const HORIZON_DAYS = 90;
|
|
@@ -42,9 +77,21 @@ const MARKET_PER_DAY = 200;
|
|
|
42
77
|
/** The server reads at most this many named companies. */
|
|
43
78
|
const MAX_SYMBOLS = 200;
|
|
44
79
|
|
|
80
|
+
const MARKET_SCOPE: EarningsScope = { kind: "all" };
|
|
81
|
+
const loadSectorHoldings = (force: boolean) => loadMembers(SECTOR_HOLDINGS_FUND, force);
|
|
82
|
+
/** A sector fund's companies the board reads, its largest first. */
|
|
83
|
+
const sectorNames = (...args: Parameters<typeof sectorSymbols>) => sectorSymbols(...args).slice(0, MAX_SYMBOLS);
|
|
84
|
+
|
|
45
85
|
type Order = "cap" | "mine";
|
|
86
|
+
type BoardView = "table" | "calendar";
|
|
87
|
+
|
|
88
|
+
const ORDER_OPTIONS: ReadonlyArray<{ value: Order; label: string }> = [{ value: "cap", label: "Size" }, { value: "mine", label: "Mine first" }];
|
|
89
|
+
/** The week as logos is for the desktop and the web; the terminal draws no logos and keeps the table. */
|
|
90
|
+
const ERN_VIEWS: ReadonlyArray<{ value: BoardView; label: string }> = [{ value: "table", label: "Table" }, { value: "calendar", label: "Calendar" }];
|
|
46
91
|
|
|
47
92
|
interface BoardData {
|
|
93
|
+
/** The query read, by `earningsCalendarKey`: kept data from another week is not this week's. */
|
|
94
|
+
queryKey: string;
|
|
48
95
|
reports: BoardReport[];
|
|
49
96
|
stale: boolean;
|
|
50
97
|
refreshError: string | null;
|
|
@@ -53,7 +100,8 @@ interface BoardData {
|
|
|
53
100
|
/**
|
|
54
101
|
* ERN without a ticker: the market's report days, largest companies first,
|
|
55
102
|
* with the implied move and each company's average move. With tickers, or the
|
|
56
|
-
*
|
|
103
|
+
* Names filter (Mine, a portfolio, a watchlist or a sector fund's holdings),
|
|
104
|
+
* the upcoming reports of those companies instead.
|
|
57
105
|
*/
|
|
58
106
|
export function EarningsBoard({ focused, width, height, scopedSymbols, highlight = null }: {
|
|
59
107
|
focused: boolean;
|
|
@@ -66,7 +114,7 @@ export function EarningsBoard({ focused, width, height, scopedSymbols, highlight
|
|
|
66
114
|
}) {
|
|
67
115
|
const dataProvider = useAssetData();
|
|
68
116
|
const { navigateTicker } = usePluginTickerActions();
|
|
69
|
-
const { createPaneFromTemplate } = usePluginAppActions();
|
|
117
|
+
const { createPaneFromTemplate, notify } = usePluginAppActions();
|
|
70
118
|
usePaneMenuItems("earnings:catalysts", () => [{ id: "catalysts", label: "Catalyst calendar", onSelect: () => createPaneFromTemplate("catalysts-pane") }], [createPaneFromTemplate]);
|
|
71
119
|
const tickers = useAppSelector((state) => state.tickers);
|
|
72
120
|
// Ticker records change for many reasons; the board reloads only when the held and watched names do.
|
|
@@ -78,60 +126,128 @@ export function EarningsBoard({ focused, width, height, scopedSymbols, highlight
|
|
|
78
126
|
() => new Map(ownedKey ? ownedKey.split(",").map((entry) => entry.split(":") as [string, "held" | "watched"]) : []),
|
|
79
127
|
[ownedKey],
|
|
80
128
|
);
|
|
81
|
-
|
|
129
|
+
// Before the Names filter, a Mine toggle; a layout saved with it on opens on Mine.
|
|
130
|
+
const [mineOnly] = usePluginPaneState<boolean>("mineOnly", false);
|
|
131
|
+
const [savedScope, setScope] = usePluginPaneState<string | null>("scope", null);
|
|
82
132
|
const [order, setOrder] = usePluginPaneState<Order>("order", "cap");
|
|
83
133
|
const [sort, setSort] = usePluginPaneState<BoardSort>("sort", { column: "cap", direction: "desc" });
|
|
84
134
|
// Keyed by symbol and date, so a reload or a shared layout keeps the row.
|
|
85
135
|
const [selectedKey, setSelectedKey] = usePluginPaneState<string | null>("selectedKey", null);
|
|
86
136
|
const [openKey, setOpenKey] = usePluginPaneState<string | null>("openEvent", null);
|
|
87
|
-
// A layout or `
|
|
137
|
+
// A layout or `gloom shot ERN NVDA,AMD --open NVDA` lands on that company's history.
|
|
88
138
|
const [openSymbol] = usePaneSettingValue<string>("open", "");
|
|
139
|
+
// A layout's `view` setting opens on the week; a choice made in the pane wins.
|
|
140
|
+
const [requestedView] = usePaneSettingValue<string>("view", "");
|
|
141
|
+
const [chosenView, setView] = usePluginPaneState<BoardView | null>("view", null);
|
|
142
|
+
// `EVTS --week last` or `--date 2026-10-15` opens on those days; a choice in the bar's Range wins. One
|
|
143
|
+
// range for both views: the table draws its days, the calendar its week (this week for the days ahead).
|
|
144
|
+
const [requestedDate] = usePaneSettingValue<string>("date", "");
|
|
145
|
+
const [requestedWeek] = usePaneSettingValue<string>("week", "");
|
|
146
|
+
const [range, setRange] = usePluginPaneState<BoardRange>("range", requestedBoardRange(requestedDate, requestedWeek));
|
|
147
|
+
// The calendar's groups opened past their "+N more" slot, by `calendarGroupKey`.
|
|
148
|
+
const [expanded, setExpanded] = useState(NONE_EXPANDED);
|
|
149
|
+
const desktop = useUiCapabilities().nativePaneChrome === true;
|
|
150
|
+
const config = usePaneAppConfig();
|
|
151
|
+
const scopeOptions = useMemo(
|
|
152
|
+
() => earningsScopeOptions({ portfolios: config.portfolios, watchlists: config.watchlists }),
|
|
153
|
+
[config.portfolios, config.watchlists],
|
|
154
|
+
);
|
|
155
|
+
const chosenScope = readEarningsScope(savedScope ?? (mineOnly ? MINE_SCOPE : ALL_SCOPE), scopeOptions);
|
|
156
|
+
// The terminal keeps its Mine toggle, so a choice only the desktop offers reads as the market there.
|
|
157
|
+
const scopeOption = desktop || chosenScope.value === MINE_SCOPE ? chosenScope : scopeOptions[0]!;
|
|
158
|
+
const scoped = scopedSymbols.length > 0;
|
|
159
|
+
const scope = scoped ? MARKET_SCOPE : scopeOption.scope;
|
|
160
|
+
const view: BoardView = !desktop ? "table"
|
|
161
|
+
: chosenView ?? (ERN_VIEWS.some((option) => option.value === requestedView) ? requestedView as BoardView : "table");
|
|
162
|
+
const calendar = view === "calendar";
|
|
89
163
|
const openedSymbol = useRef<string | null>(null);
|
|
90
164
|
const highlighted = useRef<string | null>(null);
|
|
91
165
|
|
|
92
166
|
const today = newYorkToday();
|
|
93
|
-
const market =
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
167
|
+
const market = !scoped && scope.kind === "all";
|
|
168
|
+
// Keyed by content: ticker records change for many reasons, the board reloads only when the list's names do.
|
|
169
|
+
const collectionKey = useMemo(() => {
|
|
170
|
+
if (scope.kind !== "portfolio" && scope.kind !== "watchlist") return "";
|
|
171
|
+
return [...tickers.values()]
|
|
172
|
+
.filter(({ metadata }) => (scope.kind === "portfolio" ? metadata.portfolios : metadata.watchlists).includes(scope.id))
|
|
173
|
+
.map(({ metadata }) => metadata.ticker.trim().toUpperCase())
|
|
174
|
+
.sort()
|
|
175
|
+
.join(",");
|
|
176
|
+
}, [scope, tickers]);
|
|
177
|
+
const sector = scope.kind === "sector" ? scope : null;
|
|
178
|
+
// A sector fund's companies come with its holdings, which the loader reads; the others are known here.
|
|
179
|
+
const named = useMemo(() => {
|
|
180
|
+
const names = scoped ? [...scopedSymbols]
|
|
181
|
+
: scope.kind === "portfolio" || scope.kind === "watchlist" ? (collectionKey ? collectionKey.split(",") : [])
|
|
182
|
+
: scope.kind === "sector" ? [] : [...owned.keys()];
|
|
183
|
+
return names.slice(0, MAX_SYMBOLS);
|
|
184
|
+
}, [collectionKey, owned, scope.kind, scoped, scopedSymbols]);
|
|
185
|
+
// Named companies also go to the per-ticker calendar, which covers listings the stored one does not;
|
|
186
|
+
// a sector fund's are S&P 500 companies, all in the stored one.
|
|
187
|
+
const perTicker = !market && !sector;
|
|
188
|
+
// The days ahead by default; a chosen week or day, past or ahead, for the market and for named companies alike.
|
|
189
|
+
const days = useMemo(() => (market || range ? boardRangeDays(range, today) : relativeDays(today)), [market, range, today]);
|
|
190
|
+
const weekOffset = boardRangeWeek(range, today);
|
|
191
|
+
const week = useMemo(() => calendarWeekDates(today, weekOffset), [today, weekOffset]);
|
|
192
|
+
// The calendar reads its week, reported days included; the table its days.
|
|
193
|
+
const query = useMemo<EarningsCalendarQuery>(() => calendar
|
|
194
|
+
? { from: week[0]!, to: week.at(-1)!, perDay: market ? MARKET_PER_DAY : 0, symbols: named }
|
|
195
|
+
: market || range
|
|
196
|
+
? { from: days[0]!.from, to: days.at(-1)!.to, perDay: market ? MARKET_PER_DAY : 0, symbols: named }
|
|
197
|
+
: { from: today, to: addDays(today, HORIZON_DAYS), perDay: 0, symbols: named },
|
|
198
|
+
[calendar, days, market, named, range, today, week]);
|
|
199
|
+
// A sector fund's read is named by the fund: its companies are known once its holdings are.
|
|
200
|
+
const queryKey = sector ? `${sector.etf}|${earningsCalendarKey(query)}` : earningsCalendarKey(query);
|
|
103
201
|
|
|
104
202
|
const loader = useCallback(async (force: boolean): Promise<BoardData> => {
|
|
105
|
-
|
|
106
|
-
|
|
203
|
+
const names = sector ? sectorNames((await loadSectorHoldings(force)).payload.members, sector.sectors) : named;
|
|
204
|
+
if (!market && names.length === 0) return { queryKey, reports: [], stale: false, refreshError: null };
|
|
205
|
+
const read = sector ? { ...query, symbols: names } : query;
|
|
107
206
|
const [cloud, fallback] = await Promise.allSettled([
|
|
108
|
-
loadEarningsBoard(
|
|
109
|
-
|
|
207
|
+
loadEarningsBoard(read, force),
|
|
208
|
+
!perTicker ? Promise.resolve([] as EarningsEvent[]) : loadEarningsCalendar(dataProvider, names, { force }).then((result) => result.events
|
|
209
|
+
// The per-ticker calendar is upcoming reports; a week or a chosen range keeps those in it.
|
|
210
|
+
.filter((event) => (!calendar && !range) || (event.earningsDate.toISOString().slice(0, 10) >= read.from && event.earningsDate.toISOString().slice(0, 10) <= read.to))),
|
|
110
211
|
]);
|
|
111
|
-
if (cloud.status === "rejected" && (
|
|
212
|
+
if (cloud.status === "rejected" && (!perTicker || fallback.status === "rejected")) throw cloud.reason;
|
|
112
213
|
const reports = cloud.status === "fulfilled" ? cloud.value.payload.reports.map((report) => boardReport(report, owned)) : [];
|
|
113
214
|
const covered = new Set(reports.map((report) => report.symbol));
|
|
114
215
|
const extra = fallback.status === "fulfilled"
|
|
115
|
-
? fallback.value.filter((event) => !covered.has(event.symbol)).map((event) => fallbackReport(event, owned))
|
|
216
|
+
? fallback.value.filter((event) => !covered.has(event.symbol)).map((event) => fallbackReport(event, owned, today))
|
|
116
217
|
: [];
|
|
117
218
|
return {
|
|
219
|
+
queryKey,
|
|
118
220
|
reports: [...reports, ...extra],
|
|
119
221
|
stale: cloud.status === "fulfilled" && cloud.value.stale,
|
|
120
222
|
refreshError: cloud.status === "rejected"
|
|
121
223
|
? (cloud.reason instanceof Error ? cloud.reason.message : String(cloud.reason))
|
|
122
224
|
: cloud.value.refreshError,
|
|
123
225
|
};
|
|
124
|
-
}, [dataProvider, market, named, owned, query]);
|
|
226
|
+
}, [calendar, dataProvider, market, named, owned, perTicker, query, queryKey, range, sector, today]);
|
|
125
227
|
const resource = useAsyncResource(loader, {
|
|
126
228
|
keepPreviousData: true,
|
|
127
229
|
initialData: () => {
|
|
128
|
-
const
|
|
129
|
-
|
|
230
|
+
const holdings = sector ? cachedMembers(SECTOR_HOLDINGS_FUND) : null;
|
|
231
|
+
if (sector && !holdings) return null;
|
|
232
|
+
const cached = cachedEarningsCalendar(sector && holdings ? { ...query, symbols: sectorNames(holdings.payload.members, sector.sectors) } : query);
|
|
233
|
+
return cached ? { queryKey, reports: cached.payload.reports.map((report) => boardReport(report, owned)), stale: false, refreshError: null } : null;
|
|
130
234
|
},
|
|
131
235
|
});
|
|
132
236
|
const data = resource.data;
|
|
237
|
+
// The week on screen is only the one read for it, never the last week's kept while this one loads or after it failed.
|
|
238
|
+
const weekData = data?.queryKey === queryKey ? data : null;
|
|
133
239
|
const rows = useMemo(() => boardRows(data?.reports ?? [], days, sort, order === "mine"), [data, days, order, sort]);
|
|
134
240
|
const reportRows = useMemo(() => rows.filter((row): row is BoardRow & { kind: "report" } => row.kind === "report"), [rows]);
|
|
241
|
+
const slotsPerRow = calendarSlotsPerRow(width);
|
|
242
|
+
const weekDays = useMemo(
|
|
243
|
+
() => (calendar
|
|
244
|
+
? calendarDays(weekData?.reports ?? [], week, { today, mineFirst: order === "mine", limit: slotsPerRow * CALENDAR_GROUP_ROWS, expanded })
|
|
245
|
+
: []),
|
|
246
|
+
[calendar, expanded, order, slotsPerRow, today, week, weekData],
|
|
247
|
+
);
|
|
248
|
+
const selectedReport = calendar
|
|
249
|
+
? weekData?.reports.find((report) => report.key === selectedKey) ?? null
|
|
250
|
+
: (reportRows.find((row) => row.key === selectedKey) ?? reportRows[0] ?? null)?.report ?? null;
|
|
135
251
|
const selected = reportRows.find((row) => row.key === selectedKey) ?? reportRows[0] ?? null;
|
|
136
252
|
const open = reportRows.find((row) => row.key === openKey)?.report
|
|
137
253
|
?? (openKey ? data?.reports.find((report) => report.key === openKey) : undefined) ?? null;
|
|
@@ -144,14 +260,16 @@ export function EarningsBoard({ focused, width, height, scopedSymbols, highlight
|
|
|
144
260
|
.map((row) => row.report.symbol))].join(",");
|
|
145
261
|
const reportedSymbols = useMemo(() => (reportedKey ? reportedKey.split(",") : []), [reportedKey]);
|
|
146
262
|
const liveStreaming = useLiveStreamingSetting();
|
|
147
|
-
const { quotes } = useQuoteBoard(reportedSymbols, { liveStreaming, selectedSymbol: selected?.report.symbol ?? null });
|
|
263
|
+
const { quotes } = useQuoteBoard(calendar ? NO_SYMBOLS : reportedSymbols, { liveStreaming, selectedSymbol: calendar ? null : selected?.report.symbol ?? null });
|
|
148
264
|
const quotesRef = useRef(quotes);
|
|
149
265
|
quotesRef.current = quotes;
|
|
150
266
|
const statusShown = columns.some((column) => column.id === "status");
|
|
267
|
+
const logos = desktop;
|
|
151
268
|
// Stable while the quotes tick: each row redraws by its own quote's version.
|
|
152
269
|
const renderCell = useCallback((row: BoardRow, column: BoardColumn) => {
|
|
153
270
|
const context: BoardCellContext = {
|
|
154
271
|
statusShown,
|
|
272
|
+
logos,
|
|
155
273
|
move: (report) => {
|
|
156
274
|
const state = quotesRef.current.get(report.symbol);
|
|
157
275
|
const move = reportMove(report, state?.quote, today);
|
|
@@ -159,7 +277,7 @@ export function EarningsBoard({ focused, width, height, scopedSymbols, highlight
|
|
|
159
277
|
},
|
|
160
278
|
};
|
|
161
279
|
return renderBoardCell(row, column, context);
|
|
162
|
-
}, [statusShown, today]);
|
|
280
|
+
}, [logos, statusShown, today]);
|
|
163
281
|
const rowVersion = useCallback((row: BoardRow) => {
|
|
164
282
|
if (row.kind !== "report") return row.key;
|
|
165
283
|
const state = quotes.get(row.report.symbol);
|
|
@@ -193,7 +311,9 @@ export function EarningsBoard({ focused, width, height, scopedSymbols, highlight
|
|
|
193
311
|
stale: !!data?.stale,
|
|
194
312
|
info: data && updatedAgo ? [{ id: "updated", parts: [{ text: updatedAgo, tone: "muted" as const }] }] : [],
|
|
195
313
|
});
|
|
196
|
-
const symbol = open?.symbol ??
|
|
314
|
+
const symbol = open?.symbol ?? selectedReport?.symbol ?? null;
|
|
315
|
+
// The desktop and the web only: the terminal's footer stays as it was.
|
|
316
|
+
const alerts = desktop && getSharedRegistry()?.commands.has("set-event-alert") === true;
|
|
197
317
|
usePaneFooter("earnings-actions", () => ({
|
|
198
318
|
order: 10,
|
|
199
319
|
hints: symbol
|
|
@@ -203,27 +323,112 @@ export function EarningsBoard({ focused, width, height, scopedSymbols, highlight
|
|
|
203
323
|
{ id: "estimates", key: "e", label: "stimates", onPress: () => createPaneFromTemplate("earnings-estimates-pane", { symbol }) },
|
|
204
324
|
{ id: "calls", key: "c", label: "alls", onPress: () => createPaneFromTemplate("earnings-calls-pane", { symbol }) },
|
|
205
325
|
{ id: "analysts", key: "a", label: "nalysts", onPress: () => createPaneFromTemplate("analyst-research-pane", { symbol }) },
|
|
326
|
+
// ALRT's earnings alert, set to go off when the results are out.
|
|
327
|
+
...(alerts ? [{ id: "alert", key: "n", label: "otify", title: "Earnings alert", onPress: () => {
|
|
328
|
+
if (!openEarningsAlert(symbol)) notify({ body: "Open this from the main window.", type: "info" });
|
|
329
|
+
} }] : []),
|
|
206
330
|
]
|
|
207
331
|
: [],
|
|
208
|
-
}), [createPaneFromTemplate, navigateTicker, symbol]);
|
|
332
|
+
}), [alerts, createPaneFromTemplate, navigateTicker, notify, symbol]);
|
|
209
333
|
|
|
210
|
-
// t, e, c and
|
|
334
|
+
// t, e, c, a and n are footer hints, which bind their own keys.
|
|
211
335
|
const handleKeyDown = useCallback((event: DataTableKeyEvent) => handleRefreshKey(event, () => void resource.reload()), [resource.reload]);
|
|
336
|
+
usePaneRefreshKey(() => void resource.reload(), { focused, enabled: calendar && !open });
|
|
212
337
|
|
|
213
338
|
const sortColumn = (Object.entries(SORTABLE).find(([, value]) => value === sort.column)?.[0]) ?? null;
|
|
214
|
-
const
|
|
339
|
+
const mineFilter: QueryBarFilter[] = scoped ? [] : [
|
|
340
|
+
{ id: "mine", kind: "toggle", label: "Mine", value: scope.kind === "mine", defaultValue: false, onChange: (mine: boolean) => setScope(mine ? MINE_SCOPE : ALL_SCOPE) },
|
|
341
|
+
];
|
|
342
|
+
// The desktop's Mine is one choice of the Names filter, beside each portfolio, watchlist and sector fund.
|
|
343
|
+
const namesFilter: QueryBarFilter[] = scoped ? [] : [{
|
|
344
|
+
id: "names",
|
|
345
|
+
label: "Names",
|
|
346
|
+
value: scopeOption.value,
|
|
347
|
+
defaultValue: ALL_SCOPE,
|
|
348
|
+
options: scopeOptions.map(({ value, label, description }) => ({ value, label, description })),
|
|
349
|
+
onChange: (value: string) => setScope(value),
|
|
350
|
+
}];
|
|
351
|
+
const orderView: QueryBarView<Order> = { value: order, options: ORDER_OPTIONS, onChange: setOrder };
|
|
352
|
+
// The weeks the bar offers, last week to three ahead, and the one on screen when it is another.
|
|
353
|
+
const weekOptions = (shown: number | null) => [...new Set([...CALENDAR_WEEK_OFFSETS, ...(shown == null ? [] : [shown])])]
|
|
354
|
+
.sort((left, right) => left - right)
|
|
355
|
+
.map((offset) => ({ value: String(offset), label: calendarWeekLabel(today, offset) }));
|
|
356
|
+
// One Range for both views. The table's: the days ahead, a week, or a day asked for (`--date`), which stays a
|
|
357
|
+
// choice once the bar moves off it. The calendar's: the week it draws, a day's own week.
|
|
358
|
+
const rangeDates = [...new Set([requestedDate, range].filter(isBoardRangeDay))];
|
|
359
|
+
const rangeFilter: QueryBarFilter = calendar
|
|
360
|
+
? { id: "range", label: "Range", value: String(weekOffset), options: weekOptions(weekOffset), onChange: setRange }
|
|
361
|
+
: {
|
|
362
|
+
id: "range",
|
|
363
|
+
label: "Range",
|
|
364
|
+
value: range,
|
|
365
|
+
defaultValue: "",
|
|
366
|
+
options: [
|
|
367
|
+
{ value: "", label: "Upcoming" },
|
|
368
|
+
...weekOptions(range && !isBoardRangeDay(range) ? weekOffset : null),
|
|
369
|
+
...rangeDates.map((date) => ({ value: date, label: boardRangeLabel(date, today)! })),
|
|
370
|
+
],
|
|
371
|
+
onChange: (value: string) => { setRange(value); setSelectedKey(null); },
|
|
372
|
+
};
|
|
373
|
+
// On the desktop the view picks the table or the week, and the order is a filter beside the names and the Range.
|
|
374
|
+
const queryBar = !desktop ? <QueryBar width={width} filters={[...mineFilter, rangeFilter]} view={orderView} /> : (
|
|
215
375
|
<QueryBar
|
|
216
376
|
width={width}
|
|
217
|
-
filters={
|
|
218
|
-
|
|
377
|
+
filters={[
|
|
378
|
+
...namesFilter,
|
|
379
|
+
rangeFilter,
|
|
380
|
+
{ id: "order", label: "Order", inline: true, value: order, options: ORDER_OPTIONS, onChange: setOrder },
|
|
219
381
|
]}
|
|
220
|
-
view={{
|
|
221
|
-
value: order,
|
|
222
|
-
options: [{ value: "cap", label: "Size" }, { value: "mine", label: "Mine first" }],
|
|
223
|
-
onChange: (value: Order) => setOrder(value),
|
|
224
|
-
}}
|
|
382
|
+
view={{ value: view, options: ERN_VIEWS, onChange: setView }}
|
|
225
383
|
/>
|
|
226
384
|
);
|
|
385
|
+
// "last week", "on Thu Oct 15", "in the week of Nov 2": the days the empty board or week is of.
|
|
386
|
+
const rangeWords = calendar ? boardRangeWords(String(weekOffset), today) : boardRangeWords(range, today);
|
|
387
|
+
const emptyStateTitle = market ? `No reports on the calendar ${rangeWords ?? "these days"}.`
|
|
388
|
+
: scope.kind === "mine" && named.length === 0 ? "No portfolio or watchlist names."
|
|
389
|
+
: (scope.kind === "portfolio" || scope.kind === "watchlist") && named.length === 0 ? `No tickers in ${scope.name}.`
|
|
390
|
+
: rangeWords ? `No reports from these companies ${rangeWords}.` : "No upcoming reports.";
|
|
391
|
+
const history = open ? (
|
|
392
|
+
<EarningsHistoryView key={open.symbol} symbol={open.symbol} width={width} height={Math.max(4, height - 1)}
|
|
393
|
+
focused={focused} registrationId="earnings-history" />
|
|
394
|
+
) : null;
|
|
395
|
+
|
|
396
|
+
if (calendar) {
|
|
397
|
+
// The query bar stays up while a week loads or fails, so another week or the table is a click away.
|
|
398
|
+
return (
|
|
399
|
+
<PageStackView
|
|
400
|
+
focused={focused}
|
|
401
|
+
detailOpen={!!open}
|
|
402
|
+
onBack={() => setOpenKey(null)}
|
|
403
|
+
detailTitle={open ? `${open.symbol} · ${open.name}` : undefined}
|
|
404
|
+
rootContent={(
|
|
405
|
+
<Box flexDirection="column" {...FILL_REST}>
|
|
406
|
+
{queryBar}
|
|
407
|
+
<EarningsCalendarView
|
|
408
|
+
days={weekDays}
|
|
409
|
+
width={width}
|
|
410
|
+
focused={focused && !open}
|
|
411
|
+
selectedKey={selectedKey}
|
|
412
|
+
onSelect={setSelectedKey}
|
|
413
|
+
onOpen={(report) => setOpenKey(report.key)}
|
|
414
|
+
onMore={(day, group) => {
|
|
415
|
+
// The group draws in full, the cursor on the first company its last slot counted.
|
|
416
|
+
const all = calendarDays(weekData?.reports ?? [], [day.date], { today, mineFirst: order === "mine" })[0]
|
|
417
|
+
?.groups.find((entry) => entry.session === group.session);
|
|
418
|
+
setExpanded((current) => new Set(current).add(calendarGroupKey(day.date, group.session)));
|
|
419
|
+
const next = all?.reports[group.reports.length];
|
|
420
|
+
if (next) setSelectedKey(next.key);
|
|
421
|
+
}}
|
|
422
|
+
loading={!weekData && !resource.error}
|
|
423
|
+
error={weekData ? null : resource.error}
|
|
424
|
+
emptyTitle={emptyStateTitle}
|
|
425
|
+
/>
|
|
426
|
+
</Box>
|
|
427
|
+
)}
|
|
428
|
+
detailContent={history}
|
|
429
|
+
/>
|
|
430
|
+
);
|
|
431
|
+
}
|
|
227
432
|
|
|
228
433
|
return (
|
|
229
434
|
<PaneStatusBody loading={resource.loading && !data} error={!data ? resource.error : null} subject="the earnings calendar">
|
|
@@ -257,16 +462,14 @@ export function EarningsBoard({ focused, width, height, scopedSymbols, highlight
|
|
|
257
462
|
detailOpen={!!open}
|
|
258
463
|
onBack={() => setOpenKey(null)}
|
|
259
464
|
detailTitle={open ? `${open.symbol} · ${open.name}` : undefined}
|
|
260
|
-
detailContent={
|
|
261
|
-
|
|
262
|
-
focused={focused} registrationId="earnings-history" />
|
|
263
|
-
) : null}
|
|
264
|
-
emptyStateTitle={
|
|
265
|
-
market ? "No reports on the calendar these days."
|
|
266
|
-
: named.length === 0 ? "No portfolio or watchlist names."
|
|
267
|
-
: "No upcoming reports."
|
|
268
|
-
}
|
|
465
|
+
detailContent={history}
|
|
466
|
+
emptyStateTitle={emptyStateTitle}
|
|
269
467
|
/>
|
|
270
468
|
</PaneStatusBody>
|
|
271
469
|
);
|
|
272
470
|
}
|
|
471
|
+
|
|
472
|
+
/** ALRT's form for an earnings alert on `symbol`, set to go off when the results are out. */
|
|
473
|
+
function openEarningsAlert(symbol: string): boolean {
|
|
474
|
+
return openFormModal({ kind: "plugin-command", commandId: "set-event-alert", values: earningsResultsAlertValues(symbol) });
|
|
475
|
+
}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import type { EarningsTiming } from "../../../api-client/earnings";
|
|
2
|
+
import { addDays, isSession, marketDays, ownershipRank, type BoardReport, type MarketDay } from "./board-model";
|
|
3
|
+
import { shortDate, weekday } from "./format";
|
|
4
|
+
|
|
5
|
+
/** The weeks the calendar view offers, from the one before this week to three ahead. */
|
|
6
|
+
export const CALENDAR_WEEK_OFFSETS = [-1, 0, 1, 2, 3] as const;
|
|
7
|
+
type CalendarWeekOffset = (typeof CALENDAR_WEEK_OFFSETS)[number];
|
|
8
|
+
|
|
9
|
+
/** Within a day, reports before the open come first, then during the session, after the close, and those with no time yet. */
|
|
10
|
+
const SESSIONS: ReadonlyArray<{ session: EarningsTiming | null; label: string }> = [
|
|
11
|
+
{ session: "bmo", label: "Before open" },
|
|
12
|
+
{ session: "dmh", label: "During market" },
|
|
13
|
+
{ session: "amc", label: "After close" },
|
|
14
|
+
{ session: null, label: "Time not set" },
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
export interface CalendarGroup {
|
|
18
|
+
session: EarningsTiming | null;
|
|
19
|
+
label: string;
|
|
20
|
+
/** The ones drawn, largest first (held, then watched names lead when the board puts mine first). */
|
|
21
|
+
reports: BoardReport[];
|
|
22
|
+
/** Reports of this group past its limit, counted in its last slot until the group is expanded. */
|
|
23
|
+
more: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Names a day's group, so a "+N more" slot can expand that group alone. */
|
|
27
|
+
export function calendarGroupKey(date: string, session: EarningsTiming | null): string {
|
|
28
|
+
return `${date}:${session ?? "unset"}`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface CalendarDay {
|
|
32
|
+
date: string;
|
|
33
|
+
/** "Mon" */
|
|
34
|
+
weekday: string;
|
|
35
|
+
/** "Oct 20" */
|
|
36
|
+
label: string;
|
|
37
|
+
today: boolean;
|
|
38
|
+
/** No NYSE session that day. */
|
|
39
|
+
closed: boolean;
|
|
40
|
+
/** Every report that day, drawn or not. */
|
|
41
|
+
total: number;
|
|
42
|
+
/** Only the sessions with a report. */
|
|
43
|
+
groups: CalendarGroup[];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Monday to Friday of the week `offset` weeks from the one `today` falls in;
|
|
48
|
+
* on a Saturday or Sunday "this week" is the one about to start.
|
|
49
|
+
*/
|
|
50
|
+
export function calendarWeekDates(today: string, offset: number): string[] {
|
|
51
|
+
const day = new Date(`${today}T00:00:00Z`).getUTCDay();
|
|
52
|
+
const monday = addDays(today, day === 0 ? 1 : day === 6 ? 2 : 1 - day);
|
|
53
|
+
const start = addDays(monday, offset * 7);
|
|
54
|
+
return [0, 1, 2, 3, 4].map((index) => addDays(start, index));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** "Last week", "This week", "Next week", then "Week of Nov 3". */
|
|
58
|
+
export function calendarWeekLabel(today: string, offset: number): string {
|
|
59
|
+
if (offset === -1) return "Last week";
|
|
60
|
+
if (offset === 0) return "This week";
|
|
61
|
+
if (offset === 1) return "Next week";
|
|
62
|
+
return `Week of ${shortDate(calendarWeekDates(today, offset)[0]!)}`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** The weeks `--week` names, as offsets from this week. */
|
|
66
|
+
export const BOARD_WEEKS = ["last", "this", "next"] as const;
|
|
67
|
+
export type BoardWeek = typeof BOARD_WEEKS[number];
|
|
68
|
+
const BOARD_WEEK_OFFSET: Record<BoardWeek, CalendarWeekOffset> = { last: -1, this: 0, next: 1 };
|
|
69
|
+
|
|
70
|
+
export function isBoardWeek(value: unknown): value is BoardWeek {
|
|
71
|
+
return typeof value === "string" && (BOARD_WEEKS as readonly string[]).includes(value);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* The days a board shows, as the pane's Range saves them: "" for the days
|
|
76
|
+
* ahead (the default), a week as its offset from this one ("-1" last week,
|
|
77
|
+
* "2" the week after next), or one day as YYYY-MM-DD. The table draws a
|
|
78
|
+
* section per day of it; the calendar draws its week.
|
|
79
|
+
*/
|
|
80
|
+
export type BoardRange = string;
|
|
81
|
+
|
|
82
|
+
const ISO_DAY = /^\d{4}-\d{2}-\d{2}$/;
|
|
83
|
+
const WEEK_OFFSET = /^-?\d+$/;
|
|
84
|
+
|
|
85
|
+
/** The range `--date` or `--week` asks for; the days ahead without either. */
|
|
86
|
+
export function requestedBoardRange(date: unknown, week: unknown): BoardRange {
|
|
87
|
+
if (typeof date === "string" && ISO_DAY.test(date)) return date;
|
|
88
|
+
return isBoardWeek(week) ? String(BOARD_WEEK_OFFSET[week]) : "";
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** A range that is one day (`--date`), not a week or the days ahead. */
|
|
92
|
+
export function isBoardRangeDay(range: BoardRange): boolean {
|
|
93
|
+
return ISO_DAY.test(range);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function mondayOf(date: string): string {
|
|
97
|
+
return calendarWeekDates(date, 0)[0]!;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** The week a range falls in, from this week: a day's own week, and this week for the days ahead. */
|
|
101
|
+
export function boardRangeWeek(range: BoardRange, today: string): number {
|
|
102
|
+
if (WEEK_OFFSET.test(range)) return Number(range);
|
|
103
|
+
if (!ISO_DAY.test(range)) return 0;
|
|
104
|
+
return Math.round((Date.parse(mondayOf(range)) - Date.parse(mondayOf(today))) / (7 * 86_400_000));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** A day of a week or the day asked for: "Today" for today, otherwise "Thu Oct 15". */
|
|
108
|
+
function dayLabel(date: string, today: string): string {
|
|
109
|
+
return date === today ? "Today" : `${weekday(date)} ${shortDate(date)}`;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* The table's sections for `range`: the market's days ahead by default, one
|
|
114
|
+
* section per weekday of a week, or the one day asked for. Days without
|
|
115
|
+
* reports (a holiday) leave no section.
|
|
116
|
+
*/
|
|
117
|
+
export function boardRangeDays(range: BoardRange, today: string): MarketDay[] {
|
|
118
|
+
if (ISO_DAY.test(range)) return [{ label: dayLabel(range, today), from: range, to: range }];
|
|
119
|
+
if (!WEEK_OFFSET.test(range)) return marketDays(today);
|
|
120
|
+
return calendarWeekDates(today, Number(range)).map((date) => ({ label: dayLabel(date, today), from: date, to: date }));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** What the range reads as: "Last week", "Week of Nov 2", "Thu Oct 15", or null for the days ahead. */
|
|
124
|
+
export function boardRangeLabel(range: BoardRange, today: string): string | null {
|
|
125
|
+
if (ISO_DAY.test(range)) return dayLabel(range, today);
|
|
126
|
+
return WEEK_OFFSET.test(range) ? calendarWeekLabel(today, Number(range)) : null;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** The range in a sentence ("No reports … last week"): "today", "on Thu Oct 15", "in the week of Nov 2"; null for the days ahead. */
|
|
130
|
+
export function boardRangeWords(range: BoardRange, today: string): string | null {
|
|
131
|
+
if (ISO_DAY.test(range)) return range === today ? "today" : `on ${dayLabel(range, today)}`;
|
|
132
|
+
if (!WEEK_OFFSET.test(range)) return null;
|
|
133
|
+
const offset = Number(range);
|
|
134
|
+
return offset >= -1 && offset <= 1 ? calendarWeekLabel(today, offset).toLowerCase() : `in the week of ${shortDate(calendarWeekDates(today, offset)[0]!)}`;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function bySize(left: BoardReport, right: BoardReport, mineFirst: boolean): number {
|
|
138
|
+
const rank = ownershipRank(left, mineFirst) - ownershipRank(right, mineFirst);
|
|
139
|
+
if (rank !== 0) return rank;
|
|
140
|
+
// Missing caps sink, as they do in the table.
|
|
141
|
+
if (left.marketCap !== right.marketCap) {
|
|
142
|
+
if (left.marketCap == null) return 1;
|
|
143
|
+
if (right.marketCap == null) return -1;
|
|
144
|
+
return right.marketCap - left.marketCap;
|
|
145
|
+
}
|
|
146
|
+
return left.symbol.localeCompare(right.symbol);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* The week as the calendar draws it: a column per day, and in each the
|
|
151
|
+
* reports grouped by when they come out, before the open, during the
|
|
152
|
+
* session, after the close, and with no time yet. A group takes at most
|
|
153
|
+
* `limit` slots: past it, its largest companies and a last slot that counts
|
|
154
|
+
* the rest. A group named in `expanded` (see `calendarGroupKey`) draws all
|
|
155
|
+
* of its reports.
|
|
156
|
+
*/
|
|
157
|
+
export function calendarDays(
|
|
158
|
+
reports: readonly BoardReport[],
|
|
159
|
+
dates: readonly string[],
|
|
160
|
+
{ today, mineFirst = false, limit = Number.POSITIVE_INFINITY, expanded }: {
|
|
161
|
+
today: string;
|
|
162
|
+
mineFirst?: boolean;
|
|
163
|
+
limit?: number;
|
|
164
|
+
expanded?: ReadonlySet<string>;
|
|
165
|
+
},
|
|
166
|
+
): CalendarDay[] {
|
|
167
|
+
return dates.map((date) => {
|
|
168
|
+
const inDay = reports.filter((report) => report.date === date);
|
|
169
|
+
const groups = SESSIONS.flatMap(({ session, label }): CalendarGroup[] => {
|
|
170
|
+
const inGroup = inDay.filter((report) => report.timing === session).sort((left, right) => bySize(left, right, mineFirst));
|
|
171
|
+
if (inGroup.length === 0) return [];
|
|
172
|
+
// Past the limit, the last slot counts the rest.
|
|
173
|
+
const shown = inGroup.length > limit && !expanded?.has(calendarGroupKey(date, session))
|
|
174
|
+
? inGroup.slice(0, Math.max(0, limit - 1))
|
|
175
|
+
: inGroup;
|
|
176
|
+
return [{ session, label, reports: shown, more: inGroup.length - shown.length }];
|
|
177
|
+
});
|
|
178
|
+
return {
|
|
179
|
+
date,
|
|
180
|
+
weekday: weekday(date),
|
|
181
|
+
label: shortDate(date),
|
|
182
|
+
today: date === today,
|
|
183
|
+
closed: !isSession(date),
|
|
184
|
+
total: inDay.length,
|
|
185
|
+
groups,
|
|
186
|
+
};
|
|
187
|
+
});
|
|
188
|
+
}
|