gloomberb 0.16.5 → 0.17.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/package.json +3 -1
- package/src/api-client/central-bank-rates.ts +6 -1
- package/src/api-client/chat-pane-link.ts +47 -0
- package/src/api-client/chat.ts +35 -1
- package/src/api-client/credit-boards.ts +2 -0
- package/src/api-client/data.ts +85 -1
- package/src/api-client/equity-screener.ts +3 -0
- package/src/api-client/europe-energy.ts +197 -0
- package/src/api-client/index.ts +15 -0
- package/src/api-client/letters.ts +41 -0
- package/src/api-client/market-discovery.ts +3 -0
- package/src/api-client/normalizers.ts +68 -6
- package/src/api-client/organization-tickers.ts +44 -0
- package/src/api-client/perps.ts +8 -0
- package/src/api-client/request.ts +11 -2
- package/src/api-client/socket.ts +29 -0
- package/src/api-client/themes.ts +22 -1
- package/src/api-client/types.ts +88 -2
- package/src/app/global-shortcuts.ts +35 -1
- package/src/app/keybindings/actions.ts +12 -1
- package/src/app/pane-runtime/plugin-bindings.ts +2 -2
- package/src/app/pane-runtime/ticker-open-runtime.ts +9 -3
- package/src/app/runtime/desktop-deeplink.ts +58 -20
- package/src/app/runtime/startup.ts +1 -1
- package/src/app.tsx +6 -0
- package/src/architecture/core-builtin-allowlist.json +5 -14
- package/src/architecture/dom-cell-metrics-allowlist.json +28 -0
- package/src/ask-gloom/pane-context.ts +118 -0
- package/src/ask-gloom/pane-request.ts +70 -0
- package/src/ask-gloom/pane-text.ts +201 -0
- package/src/capabilities/chart-series.ts +8 -1
- package/src/capabilities/factories.ts +1 -0
- package/src/cli/central-bank-events.ts +23 -0
- package/src/cli/command-options.ts +17 -5
- package/src/cli/commands/crypto-hints.ts +28 -2
- package/src/cli/commands/fred-series.ts +155 -4
- package/src/cli/commands/market.ts +175 -35
- package/src/cli/commands/overview.ts +62 -20
- package/src/cli/commands/search.ts +254 -23
- package/src/cli/commands/ticker.ts +137 -24
- package/src/cli/desktop-pane-shot-view.ts +114 -0
- package/src/cli/desktop-pane-shot.ts +53 -37
- package/src/cli/entry.ts +7 -0
- package/src/cli/errors.ts +7 -5
- package/src/cli/exit-codes.ts +8 -0
- package/src/cli/export-source.ts +101 -0
- package/src/cli/freshness.ts +18 -3
- package/src/cli/glossary.ts +79 -8
- package/src/cli/help.ts +10 -0
- package/src/cli/helpers.ts +2 -5
- package/src/cli/history-rows.ts +244 -13
- package/src/cli/index.ts +9 -3
- package/src/cli/known-gaps.ts +76 -8
- package/src/cli/listing-arg.ts +201 -90
- package/src/cli/listing-suggestion.ts +159 -0
- package/src/cli/native-smoke.ts +13 -0
- package/src/cli/not-a-ticker.ts +24 -4
- package/src/cli/pane-functions/access-gate.ts +8 -2
- package/src/cli/pane-functions/capabilities.ts +17 -9
- package/src/cli/pane-functions/catalog.ts +183 -39
- package/src/cli/pane-functions/data.ts +30 -0
- package/src/cli/pane-functions/dom.ts +44 -14
- package/src/cli/pane-functions/freshness.ts +48 -24
- package/src/cli/pane-functions/function-help.ts +66 -12
- package/src/cli/pane-functions/headless.ts +81 -22
- package/src/cli/pane-functions/index.ts +90 -18
- package/src/cli/pane-functions/options.ts +8 -0
- package/src/cli/pane-functions/report-notices.ts +6 -3
- package/src/cli/pane-functions/report.ts +16 -2
- package/src/cli/pane-functions/resolver.ts +32 -11
- package/src/cli/pane-functions/screenshot.ts +145 -9
- package/src/cli/perpetual-contract.ts +60 -0
- package/src/cli/registry.ts +3 -1
- package/src/cli/report-tables.ts +53 -13
- package/src/cli/result.ts +91 -17
- package/src/cli/series-search.ts +111 -0
- package/src/cli/staged-tickers.ts +1 -1
- package/src/cli/symbol-args.ts +18 -0
- package/src/cli/symbol-list.ts +1 -19
- package/src/cli/symbol-rows.ts +171 -0
- package/src/cli/ticker-resolution.ts +99 -8
- package/src/components/chart/composite/axis-overlays.tsx +10 -1
- package/src/components/chart/composite/composite-chart.tsx +24 -15
- package/src/components/chart/composite/downsample.ts +1 -1
- package/src/components/chart/composite/format.ts +29 -0
- package/src/components/chart/composite/interactions.ts +9 -2
- package/src/components/chart/composite/legend.tsx +57 -33
- package/src/components/chart/composite/panel-bitmap.ts +70 -35
- package/src/components/chart/composite/panel-labels.ts +18 -17
- package/src/components/chart/composite/panel-series.ts +1 -0
- package/src/components/chart/composite/panel-surface.tsx +6 -8
- package/src/components/chart/composite/price-axis-labels.tsx +1 -0
- package/src/components/chart/composite/rasterizer.ts +50 -8
- package/src/components/chart/composite/scene.ts +2 -1
- package/src/components/chart/composite/time-scale.ts +26 -9
- package/src/components/chart/composite/types.ts +18 -0
- package/src/components/chart/composite/use-composite-viewport.ts +30 -2
- package/src/components/chart/native/raster/crosshair.ts +8 -3
- package/src/components/chart/native/raster/primitives.ts +85 -21
- package/src/components/chart/native/surface/manager.ts +33 -8
- package/src/components/chart/surface3d/chart.tsx +1 -1
- package/src/components/command-bar/action-runtime.ts +1 -1
- package/src/components/command-bar/commands/collection-list.ts +210 -0
- package/src/components/command-bar/commands/collection.ts +40 -1
- package/src/components/command-bar/commands/direct/index.ts +4 -0
- package/src/components/command-bar/commands/registry.ts +8 -0
- package/src/components/command-bar/list/model.ts +2 -0
- package/src/components/command-bar/pane-templates/items.ts +1 -1
- package/src/components/command-bar/routes/root/plugin-install.ts +4 -4
- package/src/components/command-bar/routes/ticker-search/actions.ts +1 -0
- package/src/components/command-bar/routes/ticker-search/results.ts +3 -1
- package/src/components/command-bar/routing/actions.ts +1 -1
- package/src/components/command-bar/workflow/ops.ts +8 -97
- package/src/components/command-bar/workflow/pane-reuse.ts +177 -0
- package/src/components/command-bar/workflow/tickers.ts +35 -29
- package/src/components/data-table/view.tsx +1 -0
- package/src/components/feed-data-table/stack-view.tsx +18 -42
- package/src/components/layout/detached-pane-shell.tsx +59 -39
- package/src/components/layout/floating-pane.tsx +7 -1
- package/src/components/layout/header.tsx +5 -0
- package/src/components/layout/missing-pane.tsx +5 -3
- package/src/components/layout/pane/capture-stamp.ts +41 -0
- package/src/components/layout/pane/capture-status.ts +12 -0
- package/src/components/layout/pane/footer/keyboard.ts +3 -0
- package/src/components/layout/pane/footer/model.ts +7 -1
- package/src/components/layout/pane/header.tsx +26 -0
- package/src/components/layout/pane/index.tsx +9 -1
- package/src/components/layout/pane/sidebar.tsx +10 -11
- package/src/components/layout/shell/cursor-occlusion.ts +2 -1
- package/src/components/layout/shell/index.tsx +62 -60
- package/src/components/layout/shell/menu.ts +9 -1
- package/src/components/layout/shell/pane/actions.ts +32 -10
- package/src/components/layout/shell/pane/ask.ts +136 -0
- package/src/components/layout/shell/pane/capture.ts +136 -0
- package/src/components/layout/shell/pane/layers.tsx +26 -5
- package/src/components/layout/shell/pane/management-shortcuts.ts +46 -1
- package/src/components/layout/shell/shortcuts.ts +21 -4
- package/src/components/markdown-text.tsx +37 -6
- package/src/components/metric-treemap/heat-surface.tsx +1 -3
- package/src/components/reader/article-reader.tsx +467 -0
- package/src/components/reader/article-text.ts +527 -0
- package/src/components/reader/detail-reader.tsx +210 -0
- package/src/components/reader/reader-text.tsx +239 -0
- package/src/components/table-view-shared.tsx +8 -4
- package/src/components/ticker/badge/list.tsx +15 -4
- package/src/components/ticker/list-table-view.tsx +19 -1
- package/src/components/ui/choice-dialog.tsx +3 -0
- package/src/components/ui/data-table/index.tsx +1 -0
- package/src/components/ui/data-table/types.ts +7 -0
- package/src/components/ui/detail-scroll-body.tsx +31 -4
- package/src/components/ui/display.tsx +46 -1
- package/src/components/ui/icon.tsx +14 -1
- package/src/components/ui/list-view.tsx +3 -1
- package/src/components/ui/query-bar-keys.tsx +2 -0
- package/src/components/ui/query-bar.tsx +18 -1
- package/src/components/ui/select-button.tsx +3 -0
- package/src/data/config/store/fold-panes.ts +202 -11
- package/src/data/config/store/migrations.ts +20 -1
- package/src/data/config/store/portfolio-as-of-column.ts +57 -0
- package/src/docs/snapshot.json +191 -23
- package/src/i18n/es.ts +18 -1
- package/src/i18n/ja.ts +18 -1
- package/src/i18n/ko.ts +18 -1
- package/src/i18n/zh-cn.ts +18 -1
- package/src/i18n/zh-tw.ts +18 -1
- package/src/layout/desk-keys.ts +7 -0
- package/src/layout/desks.ts +2 -2
- package/src/layout-marketplace/gallery.tsx +1 -1
- package/src/market-data/market/freshness.ts +3 -2
- package/src/market-data/market/session-close-note.ts +3 -2
- package/src/market-data/market/status.ts +67 -6
- package/src/market-data/quotes/contributions.ts +17 -0
- package/src/market-data/quotes/metadata.ts +12 -0
- package/src/market-data/quotes/regular-session-valuation.ts +131 -0
- package/src/market-data/quotes/resolution.ts +7 -0
- package/src/market-data/snapshot-provider.ts +6 -3
- package/src/notifications/app-badge.ts +30 -0
- package/src/notifications/app-notifier.ts +17 -1
- package/src/notifications/notification-log.ts +180 -0
- package/src/plugins/auto-update-node.ts +2 -2
- package/src/plugins/auto-update.ts +2 -2
- package/src/plugins/builtin/account-management/calendar-tab.tsx +1 -1
- package/src/plugins/builtin/account-management/form-components.tsx +53 -1
- package/src/plugins/builtin/account-management/index.tsx +1 -0
- package/src/plugins/builtin/account-management/keyboard.ts +5 -0
- package/src/plugins/builtin/account-management/model.ts +27 -0
- package/src/plugins/builtin/account-management/pane.tsx +62 -2
- package/src/plugins/builtin/alerts/catalysts.ts +1 -1
- package/src/plugins/builtin/alerts/cli.ts +6 -4
- package/src/plugins/builtin/alerts/focus.ts +27 -0
- package/src/plugins/builtin/alerts/index.tsx +6 -2
- package/src/plugins/builtin/alerts/pane.tsx +19 -1
- package/src/plugins/builtin/analytics/index.tsx +5 -2
- package/src/plugins/builtin/analytics/risk-headless.ts +30 -15
- package/src/plugins/builtin/attention/headless.ts +1 -1
- package/src/plugins/builtin/awards/headless.ts +88 -18
- package/src/plugins/builtin/awards/model.ts +41 -1
- package/src/plugins/builtin/awards/pane.tsx +48 -30
- package/src/plugins/builtin/backtest/headless.ts +2 -2
- package/src/plugins/builtin/backtest/pane.tsx +2 -1
- package/src/plugins/builtin/bond-calculator/index.tsx +3 -5
- package/src/plugins/builtin/broker-manager/index.tsx +1 -0
- package/src/plugins/builtin/buildout/detail/company.tsx +7 -4
- package/src/plugins/builtin/builtin-plugin-meta.ts +5 -4
- package/src/plugins/builtin/catalysts/headless.ts +1 -1
- package/src/plugins/builtin/catalysts/model.ts +92 -10
- package/src/plugins/builtin/catalysts/pane.tsx +6 -4
- package/src/plugins/builtin/cds/client.ts +11 -31
- package/src/plugins/builtin/cds/headless.ts +5 -2
- package/src/plugins/builtin/cds/index.tsx +21 -30
- package/src/plugins/builtin/cds/model.ts +21 -1
- package/src/plugins/builtin/cds/pane.tsx +6 -4
- package/src/plugins/builtin/central-bank-rates/client.ts +4 -0
- package/src/plugins/builtin/central-bank-rates/headless.ts +46 -16
- package/src/plugins/builtin/central-bank-rates/index.tsx +1 -1
- package/src/plugins/builtin/central-bank-rates/model.ts +99 -0
- package/src/plugins/builtin/central-bank-rates/pane.tsx +1 -1
- package/src/plugins/builtin/central-bank-rates/series.ts +19 -25
- package/src/plugins/builtin/changelog/index.tsx +11 -12
- package/src/plugins/builtin/chart-composer/catalog-inventory.ts +1 -0
- package/src/plugins/builtin/chart-composer/headless-schema.ts +3 -1
- package/src/plugins/builtin/chart-composer/headless.ts +151 -9
- package/src/plugins/builtin/chart-composer/index.tsx +6 -1
- package/src/plugins/builtin/chart-composer/pane.tsx +84 -40
- package/src/plugins/builtin/chart-composer/session-history.ts +20 -5
- package/src/plugins/builtin/chat/command-bar.ts +6 -8
- package/src/plugins/builtin/chat/content/composer-runtime.ts +6 -1
- package/src/plugins/builtin/chat/content/composer.tsx +15 -2
- package/src/plugins/builtin/chat/content/footer.tsx +27 -5
- package/src/plugins/builtin/chat/content/handle-prompt.tsx +326 -0
- package/src/plugins/builtin/chat/content/index.tsx +201 -13
- package/src/plugins/builtin/chat/content/layout-metrics.ts +4 -0
- package/src/plugins/builtin/chat/content/new-messages.tsx +89 -0
- package/src/plugins/builtin/chat/content/open-targets.ts +20 -4
- package/src/plugins/builtin/chat/content/row-activity.ts +132 -0
- package/src/plugins/builtin/chat/content/scroll.ts +133 -28
- package/src/plugins/builtin/chat/content/shortcuts.ts +2 -2
- package/src/plugins/builtin/chat/content/transcript.tsx +155 -79
- package/src/plugins/builtin/chat/content/types.ts +1 -0
- package/src/plugins/builtin/chat/controller/fetch.ts +8 -2
- package/src/plugins/builtin/chat/controller/index.ts +121 -1
- package/src/plugins/builtin/chat/controller/message-loading.ts +3 -0
- package/src/plugins/builtin/chat/controller/messages.ts +7 -2
- package/src/plugins/builtin/chat/controller/realtime.ts +10 -1
- package/src/plugins/builtin/chat/controller/send.ts +61 -1
- package/src/plugins/builtin/chat/controller/state.ts +8 -0
- package/src/plugins/builtin/chat/ghost-user.ts +20 -0
- package/src/plugins/builtin/chat/handle-prompt.ts +128 -0
- package/src/plugins/builtin/chat/index.tsx +66 -25
- package/src/plugins/builtin/chat/layout.ts +84 -18
- package/src/plugins/builtin/chat/message/desktop.tsx +111 -14
- package/src/plugins/builtin/chat/message/header.tsx +81 -21
- package/src/plugins/builtin/chat/message/pane-chip.tsx +223 -0
- package/src/plugins/builtin/chat/message/person-icons.tsx +53 -0
- package/src/plugins/builtin/chat/message/profile-popover.tsx +77 -9
- package/src/plugins/builtin/chat/message/reactions.tsx +210 -0
- package/src/plugins/builtin/chat/message/render-state.ts +33 -4
- package/src/plugins/builtin/chat/message/terminal.tsx +72 -8
- package/src/plugins/builtin/chat/message/types.ts +15 -0
- package/src/plugins/builtin/chat/pane-links/model.ts +149 -0
- package/src/plugins/builtin/chat/pane-links/open.ts +29 -0
- package/src/plugins/builtin/chat/pane-links/previews.ts +119 -0
- package/src/plugins/builtin/chat/pane-state.ts +5 -8
- package/src/plugins/builtin/chat/people.ts +202 -0
- package/src/plugins/builtin/chat/profile-popover.ts +18 -2
- package/src/plugins/builtin/chat/reactions.ts +197 -0
- package/src/plugins/builtin/chat/share/flow.tsx +87 -0
- package/src/plugins/builtin/chat/share/targets.ts +27 -0
- package/src/plugins/builtin/chat/status-widget.tsx +7 -9
- package/src/plugins/builtin/chat/unread-badge.ts +65 -0
- package/src/plugins/builtin/chat/unread-inbox-pane.tsx +151 -27
- package/src/plugins/builtin/chat/unread-inbox.ts +22 -0
- package/src/plugins/builtin/clinical-trials/client.ts +26 -1
- package/src/plugins/builtin/clinical-trials/index.tsx +10 -2
- package/src/plugins/builtin/clinical-trials/model.ts +269 -0
- package/src/plugins/builtin/clinical-trials/pane.tsx +247 -62
- package/src/plugins/builtin/clinical-trials/sponsor-tickers.ts +156 -0
- package/src/plugins/builtin/cloud/askg/attached-pane.tsx +69 -0
- package/src/plugins/builtin/cloud/askg/pane-attachment.ts +94 -0
- package/src/plugins/builtin/cloud/askg/pane.tsx +141 -12
- package/src/plugins/builtin/cloud/askg/pending-question.ts +11 -0
- package/src/plugins/builtin/cloud/mcp-connect/dialog.tsx +1 -0
- package/src/plugins/builtin/cloud/plugin.tsx +19 -2
- package/src/plugins/builtin/cloud/team/model.ts +5 -0
- package/src/plugins/builtin/cloud/team/module.tsx +1 -0
- package/src/plugins/builtin/cloud/team/store.ts +8 -3
- package/src/plugins/builtin/cloud/thesis/module.tsx +1 -0
- package/src/plugins/builtin/comment-letters/pane.tsx +30 -11
- package/src/plugins/builtin/commodities-energy/index.tsx +179 -0
- package/src/plugins/builtin/commodity-balances/client.ts +208 -0
- package/src/plugins/builtin/commodity-balances/headless.ts +66 -0
- package/src/plugins/builtin/commodity-balances/index.tsx +32 -0
- package/src/plugins/builtin/commodity-balances/model.ts +261 -0
- package/src/plugins/builtin/commodity-balances/pane.tsx +227 -0
- package/src/plugins/builtin/company-attention/headless.ts +2 -2
- package/src/plugins/builtin/company-kpis/headless.ts +97 -10
- package/src/plugins/builtin/company-kpis/model.ts +24 -2
- package/src/plugins/builtin/company-kpis/pane.tsx +13 -14
- package/src/plugins/builtin/composite-plugins.ts +26 -1
- package/src/plugins/builtin/connections/index.ts +1 -0
- package/src/plugins/builtin/cot/headless.ts +1 -1
- package/src/plugins/builtin/cpi/headless.ts +3 -3
- package/src/plugins/builtin/credit-boards/cdx-pane.tsx +10 -1
- package/src/plugins/builtin/credit-boards/client.ts +6 -2
- package/src/plugins/builtin/credit-boards/headless.ts +108 -31
- package/src/plugins/builtin/credit-boards/index.tsx +21 -42
- package/src/plugins/builtin/credit-boards/model.ts +11 -3
- package/src/plugins/builtin/credit-conditions/client.ts +12 -9
- package/src/plugins/builtin/credit-conditions/headless.ts +13 -2
- package/src/plugins/builtin/credit-conditions/index.tsx +20 -22
- package/src/plugins/builtin/credit-conditions/model.ts +19 -11
- package/src/plugins/builtin/credit-conditions/series.ts +8 -18
- package/src/plugins/builtin/credit-documents/headless.ts +2 -2
- package/src/plugins/builtin/credit-documents/index.tsx +27 -10
- package/src/plugins/builtin/debt-maturities/headless.ts +17 -11
- package/src/plugins/builtin/debt-maturities/index.tsx +3 -17
- package/src/plugins/builtin/debug/index.tsx +2 -2
- package/src/plugins/builtin/dividend-yield/client.ts +6 -1
- package/src/plugins/builtin/dividend-yield/headless.ts +8 -3
- package/src/plugins/builtin/dividend-yield/index.tsx +1 -1
- package/src/plugins/builtin/dividend-yield/pane.tsx +6 -2
- package/src/plugins/builtin/dividend-yield/provider-client.ts +3 -1
- package/src/plugins/builtin/dividend-yield/types.ts +2 -0
- package/src/plugins/builtin/docs/blocks.tsx +4 -3
- package/src/plugins/builtin/docs/pane.tsx +16 -8
- package/src/plugins/builtin/doe/headless.ts +12 -8
- package/src/plugins/builtin/earnings/index.tsx +11 -0
- package/src/plugins/builtin/earnings-calls/headless.ts +28 -2
- package/src/plugins/builtin/earnings-calls/index.tsx +1 -1
- package/src/plugins/builtin/earnings-calls/pane.tsx +2 -12
- package/src/plugins/builtin/earnings-ripple/index.tsx +2 -0
- package/src/plugins/builtin/econ/fred-catalog.ts +9 -0
- package/src/plugins/builtin/equity-screener/client.ts +1 -1
- package/src/plugins/builtin/equity-screener/headless.ts +39 -5
- package/src/plugins/builtin/equity-screener/model.ts +121 -68
- package/src/plugins/builtin/estimate-revisions/headless.ts +3 -3
- package/src/plugins/builtin/executives/pane.tsx +3 -1
- package/src/plugins/builtin/exposure/drivers.ts +13 -0
- package/src/plugins/builtin/exposure/headless.ts +205 -13
- package/src/plugins/builtin/exposure/index.tsx +1 -0
- package/src/plugins/builtin/exposure/model.ts +23 -3
- package/src/plugins/builtin/exposure/pane.tsx +11 -11
- package/src/plugins/builtin/fear-greed/index.tsx +14 -10
- package/src/plugins/builtin/filing-events/index.tsx +20 -0
- package/src/plugins/builtin/fixed-income/index.tsx +46 -0
- package/src/plugins/builtin/fixed-income/model.ts +27 -0
- package/src/plugins/builtin/fixed-income/pane.tsx +162 -0
- package/src/plugins/builtin/fixed-income/shortcut.ts +52 -0
- package/src/plugins/builtin/futures/index.tsx +24 -7
- package/src/plugins/builtin/futures/series.ts +23 -2
- package/src/plugins/builtin/futures/use-front-returns.ts +3 -2
- package/src/plugins/builtin/futures-curve/headless.ts +1 -1
- package/src/plugins/builtin/futures-curve/index.tsx +1 -1
- package/src/plugins/builtin/futures-curve/pane.tsx +6 -4
- package/src/plugins/builtin/fx-matrix/client.ts +63 -0
- package/src/plugins/builtin/fx-matrix/export.ts +2 -1
- package/src/plugins/builtin/fx-matrix/headless.ts +154 -0
- package/src/plugins/builtin/fx-matrix/index.tsx +3 -3
- package/src/plugins/builtin/gpu/headless.ts +4 -4
- package/src/plugins/builtin/help/function-index.ts +2 -0
- package/src/plugins/builtin/help/index.tsx +14 -1
- package/src/plugins/builtin/help/shortcut-table.tsx +4 -2
- package/src/plugins/builtin/insider/detail.tsx +20 -12
- package/src/plugins/builtin/insider/index.tsx +2 -2
- package/src/plugins/builtin/ipo-calendar/headless.ts +1 -1
- package/src/plugins/builtin/iv-history/client.ts +6 -2
- package/src/plugins/builtin/iv-history/format.ts +9 -0
- package/src/plugins/builtin/iv-history/headless.ts +50 -18
- package/src/plugins/builtin/iv-history/index.tsx +3 -0
- package/src/plugins/builtin/iv-history/model.ts +35 -4
- package/src/plugins/builtin/iv-history/screen-pane.tsx +13 -5
- package/src/plugins/builtin/jobs/headless.ts +6 -8
- package/src/plugins/builtin/jodi/client.ts +220 -0
- package/src/plugins/builtin/jodi/headless.ts +63 -0
- package/src/plugins/builtin/jodi/index.tsx +32 -0
- package/src/plugins/builtin/jodi/model.ts +75 -0
- package/src/plugins/builtin/jodi/pane.tsx +141 -0
- package/src/plugins/builtin/kelly-sizer/index.tsx +2 -0
- package/src/plugins/builtin/market-heatmap/evidence.ts +13 -4
- package/src/plugins/builtin/market-heatmap/headless.ts +22 -7
- package/src/plugins/builtin/market-heatmap/index.tsx +47 -23
- package/src/plugins/builtin/market-heatmap/live.ts +2 -1
- package/src/plugins/builtin/market-heatmap/portfolio.ts +67 -21
- package/src/plugins/builtin/market-movers/table.ts +2 -2
- package/src/plugins/builtin/market-valuation/align.ts +10 -9
- package/src/plugins/builtin/members/headless.ts +1 -1
- package/src/plugins/builtin/members/pane.tsx +3 -2
- package/src/plugins/builtin/mna/distress/headless.ts +4 -4
- package/src/plugins/builtin/mna/distress/model.ts +52 -1
- package/src/plugins/builtin/mna/distress/pane.tsx +17 -12
- package/src/plugins/builtin/mna/headless.ts +3 -3
- package/src/plugins/builtin/mna/index.tsx +2 -0
- package/src/plugins/builtin/money-markets/headless.ts +5 -4
- package/src/plugins/builtin/news/index.tsx +0 -2
- package/src/plugins/builtin/news/wire/index.tsx +2 -2
- package/src/plugins/builtin/news/wire/industry-pane.tsx +28 -14
- package/src/plugins/builtin/news/wire/letters/client.ts +108 -0
- package/src/plugins/builtin/news/wire/letters/model.ts +69 -0
- package/src/plugins/builtin/news/wire/letters/pane.tsx +155 -0
- package/src/plugins/builtin/news/wire/mutes.ts +2 -1
- package/src/plugins/builtin/news/wire/news/detail-view.tsx +53 -104
- package/src/plugins/builtin/news/wire/news/footer.ts +2 -25
- package/src/plugins/builtin/news/wire/news/preset-pane.tsx +0 -2
- package/src/plugins/builtin/news/wire/news/query-presets.ts +4 -1
- package/src/plugins/builtin/notes/index.tsx +1 -0
- package/src/plugins/builtin/openfda/client.ts +123 -15
- package/src/plugins/builtin/openfda/model.ts +163 -0
- package/src/plugins/builtin/openfda/pane.tsx +109 -65
- package/src/plugins/builtin/openfda/types.ts +25 -0
- package/src/plugins/builtin/options/index.tsx +3 -0
- package/src/plugins/builtin/options/view.tsx +1 -1
- package/src/plugins/builtin/options-positioning/headless.ts +3 -3
- package/src/plugins/builtin/pe-band/model.ts +3 -2
- package/src/plugins/builtin/perps/client.ts +50 -10
- package/src/plugins/builtin/perps/equity-row.tsx +29 -16
- package/src/plugins/builtin/perps/headless.ts +2 -2
- package/src/plugins/builtin/perps/index.tsx +5 -3
- package/src/plugins/builtin/perps/list-perpetuals.ts +118 -0
- package/src/plugins/builtin/perps/open-market.ts +15 -0
- package/src/plugins/builtin/plugin-marketplace/index.tsx +1 -1
- package/src/plugins/builtin/plugin-marketplace/pane.tsx +7 -7
- package/src/plugins/builtin/plugin-module.ts +3 -1
- package/src/plugins/builtin/portfolio-list/allocation.ts +5 -4
- package/src/plugins/builtin/portfolio-list/cell-version.ts +8 -1
- package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +24 -136
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +78 -19
- package/src/plugins/builtin/portfolio-list/cli/render.ts +249 -52
- package/src/plugins/builtin/portfolio-list/cli/shared.ts +44 -12
- package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +21 -7
- package/src/plugins/builtin/portfolio-list/column-values.ts +103 -25
- package/src/plugins/builtin/portfolio-list/headless.ts +51 -15
- package/src/plugins/builtin/portfolio-list/index.tsx +5 -1
- package/src/plugins/builtin/portfolio-list/live-valuation.ts +25 -13
- package/src/plugins/builtin/portfolio-list/mutations.ts +2 -9
- package/src/plugins/builtin/portfolio-list/pane/data.ts +5 -1
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +46 -8
- package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +16 -10
- package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +21 -1
- package/src/plugins/builtin/portfolio-list/settings.ts +17 -0
- package/src/plugins/builtin/portfolio-list/summary/index.tsx +12 -0
- package/src/plugins/builtin/portfolio-list/summary/totals.ts +8 -3
- package/src/plugins/builtin/portfolio-list/table.tsx +30 -6
- package/src/plugins/builtin/power/evidence.ts +86 -8
- package/src/plugins/builtin/power/gas-client.ts +110 -0
- package/src/plugins/builtin/power/gas-model.ts +194 -0
- package/src/plugins/builtin/power/gas.tsx +145 -0
- package/src/plugins/builtin/power/headless.ts +9 -2
- package/src/plugins/builtin/power/index.tsx +35 -3
- package/src/plugins/builtin/power/model.ts +2 -2
- package/src/plugins/builtin/power/pane.tsx +7 -3
- package/src/plugins/builtin/power/prices-client.ts +139 -0
- package/src/plugins/builtin/power/prices-headless.ts +205 -0
- package/src/plugins/builtin/power/prices-model.ts +103 -0
- package/src/plugins/builtin/power/prices.tsx +202 -0
- package/src/plugins/builtin/primary-dealers/client.ts +108 -0
- package/src/plugins/builtin/primary-dealers/headless.ts +53 -0
- package/src/plugins/builtin/primary-dealers/index.tsx +17 -0
- package/src/plugins/builtin/primary-dealers/model.ts +206 -0
- package/src/plugins/builtin/primary-dealers/pane.tsx +149 -0
- package/src/plugins/builtin/rate-path/headless.ts +38 -18
- package/src/plugins/builtin/relative-rotation/headless.ts +3 -3
- package/src/plugins/builtin/relative-rotation/index.tsx +3 -0
- package/src/plugins/builtin/research/analyst-model.ts +9 -5
- package/src/plugins/builtin/research/headless-schema.ts +2 -1
- package/src/plugins/builtin/research/index.tsx +2 -0
- package/src/plugins/builtin/research/relative-valuation-headless.ts +68 -32
- package/src/plugins/builtin/research/relative-valuation-model.ts +45 -24
- package/src/plugins/builtin/research/relative-valuation-pane.tsx +39 -4
- package/src/plugins/builtin/research-search/article.ts +65 -0
- package/src/plugins/builtin/research-search/document-view.tsx +33 -215
- package/src/plugins/builtin/research-search/model.ts +0 -9
- package/src/plugins/builtin/research-search/pane.tsx +41 -30
- package/src/plugins/builtin/research-search/snippet.ts +0 -29
- package/src/plugins/builtin/revenue-breakdown/headless.ts +18 -6
- package/src/plugins/builtin/scanner/flow-pane.tsx +8 -1
- package/src/plugins/builtin/sec/filing-display.tsx +3 -36
- package/src/plugins/builtin/sec/headless.ts +25 -3
- package/src/plugins/builtin/sec/index.tsx +133 -44
- package/src/plugins/builtin/sec/model.ts +148 -2
- package/src/plugins/builtin/sec/row-summaries.ts +105 -0
- package/src/plugins/builtin/sectors/index.tsx +2 -0
- package/src/plugins/builtin/sectors/sector-model.ts +2 -2
- package/src/plugins/builtin/series-inventory.ts +3 -0
- package/src/plugins/builtin/shared/cloud-denied.ts +15 -0
- package/src/plugins/builtin/shared/free-preview.ts +47 -0
- package/src/plugins/builtin/shared/locked-rows.tsx +1 -1
- package/src/plugins/builtin/shared/report-freshness.ts +3 -1
- package/src/plugins/builtin/shared/use-quote-board.ts +179 -43
- package/src/plugins/builtin/shared/volatility/options.ts +4 -1
- package/src/plugins/builtin/shared/wall-teaser.tsx +2 -2
- package/src/plugins/builtin/shared/zip-text.ts +46 -0
- package/src/plugins/builtin/short-interest/watch-headless.ts +2 -2
- package/src/plugins/builtin/short-interest/watch-model.ts +11 -2
- package/src/plugins/builtin/short-volume/headless.ts +1 -1
- package/src/plugins/builtin/social-mentions/headless.ts +1 -1
- package/src/plugins/builtin/supply-chain/headless.ts +43 -11
- package/src/plugins/builtin/supply-chain/model.ts +13 -0
- package/src/plugins/builtin/supply-chain/pane.tsx +5 -5
- package/src/plugins/builtin/themes/headless.ts +74 -10
- package/src/plugins/builtin/themes/model.ts +71 -4
- package/src/plugins/builtin/themes/pane.tsx +22 -5
- package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +114 -0
- package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +57 -2
- package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +19 -55
- package/src/plugins/builtin/ticker-detail/financials/aggregation.ts +11 -0
- package/src/plugins/builtin/ticker-detail/financials/ratios.ts +81 -19
- package/src/plugins/builtin/ticker-detail/financials/tab.tsx +1 -1
- package/src/plugins/builtin/ticker-detail/headless-schema.ts +30 -0
- package/src/plugins/builtin/ticker-detail/headless.ts +88 -2
- package/src/plugins/builtin/ticker-detail/index.tsx +23 -11
- package/src/plugins/builtin/ticker-detail/overview/model.ts +3 -1
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +8 -6
- package/src/plugins/builtin/ticker-detail/quote-monitor/card.tsx +8 -6
- package/src/plugins/builtin/time-sales/headless.ts +23 -1
- package/src/plugins/builtin/time-sales/index.tsx +2 -1
- package/src/plugins/builtin/trace-bonds/client.ts +196 -0
- package/src/plugins/builtin/trace-bonds/headless.ts +69 -0
- package/src/plugins/builtin/trace-bonds/index.tsx +33 -0
- package/src/plugins/builtin/trace-bonds/model.ts +115 -0
- package/src/plugins/builtin/trace-bonds/pane.tsx +191 -0
- package/src/plugins/builtin/treasury-auctions/index.tsx +33 -47
- package/src/plugins/builtin/treasury-daily/client.ts +96 -0
- package/src/plugins/builtin/treasury-daily/headless.ts +69 -0
- package/src/plugins/builtin/treasury-daily/index.tsx +17 -0
- package/src/plugins/builtin/treasury-daily/model.ts +69 -0
- package/src/plugins/builtin/treasury-daily/pane.tsx +140 -0
- package/src/plugins/builtin/vol-surface/evidence.ts +7 -1
- package/src/plugins/builtin/vol-surface/headless.ts +50 -17
- package/src/plugins/builtin/vol-surface/heat-grid.tsx +113 -0
- package/src/plugins/builtin/vol-surface/model.ts +39 -6
- package/src/plugins/builtin/vol-surface/pane.tsx +14 -13
- package/src/plugins/builtin/vol-surface/stored.ts +63 -3
- package/src/plugins/builtin/vol-surface/surface.tsx +30 -2
- package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +6 -5
- package/src/plugins/builtin/world-venue-map/basemap.ts +6 -3
- package/src/plugins/builtin/world-venue-map/entity-detail.tsx +15 -2
- package/src/plugins/builtin/world-venue-map/geo-draw.tsx +2 -1
- package/src/plugins/builtin/world-venue-map/geo-svg.tsx +6 -6
- package/src/plugins/builtin/world-venue-map/layered-pane.tsx +16 -9
- package/src/plugins/builtin/world-venue-map/map.tsx +145 -13
- package/src/plugins/builtin/world-venue-map/model.ts +56 -19
- package/src/plugins/builtin/world-venue-map/pane.tsx +5 -2
- package/src/plugins/builtin/yield-curve/index.tsx +1 -1
- package/src/plugins/builtin-editorial.ts +1 -1
- package/src/plugins/catalog-browser.ts +25 -2
- package/src/plugins/installer.ts +2 -2
- package/src/plugins/loader.ts +15 -0
- package/src/plugins/manager-node.ts +1 -1
- package/src/plugins/{builtin/plugin-marketplace → marketplace}/feed.ts +2 -2
- package/src/plugins/{builtin/plugin-marketplace → marketplace}/model.ts +63 -27
- package/src/plugins/{builtin/plugin-marketplace → marketplace}/store.ts +1 -1
- package/src/plugins/registry/host-actions.ts +11 -0
- package/src/portfolio/collection-name.ts +31 -0
- package/src/portfolio/valuation-basis.ts +79 -0
- package/src/public/time-series.ts +1 -1
- package/src/react/input.ts +33 -1
- package/src/react/key-repeat.ts +86 -0
- package/src/remote/controller.ts +21 -1
- package/src/remote/schema.ts +3 -2
- package/src/renderers/browser/main.tsx +1 -1
- package/src/renderers/browser/research-entry.ts +4 -2
- package/src/renderers/dom/build-assets.ts +14 -5
- package/src/renderers/dom/data-table/index.tsx +5 -3
- package/src/renderers/dom/data-table/row.tsx +3 -0
- package/src/renderers/dom/desktop/controls.tsx +2 -1
- package/src/renderers/dom/desktop/icons.tsx +34 -0
- package/src/renderers/dom/desktop/list-view.tsx +1 -1
- package/src/renderers/dom/desktop/menu.tsx +1 -1
- package/src/renderers/dom/desktop/query-bar.tsx +3 -1
- package/src/renderers/dom/host/block-glyph-canvas.tsx +6 -3
- package/src/renderers/dom/host/box.tsx +7 -2
- package/src/renderers/dom/host/chart-surface.tsx +34 -2
- package/src/renderers/dom/host/resize-rows.ts +111 -0
- package/src/renderers/dom/host/scroll-box.tsx +32 -0
- package/src/renderers/dom/host/size-observer.ts +24 -9
- package/src/renderers/dom/host/sticky-scroll.ts +147 -0
- package/src/renderers/dom/host/style.ts +15 -1
- package/src/renderers/dom/host/surface-3d.tsx +15 -7
- package/src/renderers/dom/host/surface-fit.ts +410 -0
- package/src/renderers/dom/host/text.tsx +2 -2
- package/src/renderers/dom/input-host.tsx +1 -0
- package/src/renderers/dom/styles.css +109 -16
- package/src/renderers/electrobun/bun/application-menu/click.ts +18 -0
- package/src/renderers/electrobun/bun/desktop/app-badge.ts +37 -0
- package/src/renderers/electrobun/bun/desktop/backend.ts +1 -0
- package/src/renderers/electrobun/bun/desktop/host-requests.ts +8 -0
- package/src/renderers/electrobun/bun/desktop/macos-dock-badge.ts +37 -0
- package/src/renderers/electrobun/bun/desktop/macos-dock-icon.ts +2 -40
- package/src/renderers/electrobun/bun/desktop/macos-objc.ts +41 -0
- package/src/renderers/electrobun/bun/index.ts +3 -2
- package/src/renderers/electrobun/bun/tui-entry.ts +18 -1
- package/src/renderers/electrobun/shared/protocol.ts +3 -1
- package/src/renderers/electrobun/view/app-badge-host.ts +17 -0
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +20 -3
- package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +59 -24
- package/src/renderers/electrobun/view/main.tsx +5 -3
- package/src/renderers/electrobun/view/remote/asset-data-client.ts +7 -1
- package/src/renderers/opentui/chart-surface.tsx +1 -0
- package/src/renderers/opentui/frame-capture.ts +33 -0
- package/src/renderers/opentui/host.tsx +10 -13
- package/src/renderers/opentui/pane-image/glyphs-license.txt +107 -0
- package/src/renderers/opentui/pane-image/glyphs.json +1 -0
- package/src/renderers/opentui/pane-image/index.ts +107 -0
- package/src/renderers/opentui/pane-image/raster.ts +428 -0
- package/src/renderers/opentui/start.tsx +3 -3
- package/src/renderers/opentui/test-utils.tsx +3 -0
- package/src/renderers/opentui/ui-host.tsx +29 -1
- package/src/series/resolve.ts +3 -2
- package/src/series/types.ts +8 -0
- package/src/series/validate.ts +2 -2
- package/src/shares/api.ts +5 -1
- package/src/shares/chat.ts +34 -0
- package/src/shares/dialog.tsx +295 -0
- package/src/shares/flow.tsx +56 -0
- package/src/shares/live.ts +14 -22
- package/src/shares/location.ts +31 -0
- package/src/shares/open.ts +26 -0
- package/src/shares/pane-image.ts +164 -0
- package/src/shares/personal-pane.ts +52 -0
- package/src/shares/portable-layout.ts +4 -2
- package/src/shares/prepare.ts +20 -0
- package/src/sources/gloomberb-cloud/index.ts +109 -5
- package/src/sources/gloomberb-cloud/normalizers.ts +7 -0
- package/src/sources/gloomberb-cloud/perpetuals.ts +249 -0
- package/src/sources/history-coverage.ts +22 -4
- package/src/sources/history-result.ts +3 -1
- package/src/sources/history-retention.ts +11 -0
- package/src/sources/listing-target.ts +4 -0
- package/src/sources/provider-errors.ts +2 -1
- package/src/sources/provider-router/batches.ts +18 -2
- package/src/sources/provider-router/index.ts +16 -1
- package/src/state/app/context/index.tsx +3 -2
- package/src/state/hooks/inline-tickers.ts +49 -11
- package/src/test-support/builtin-panes.ts +31 -0
- package/src/test-support/shell-pane-keys.tsx +1 -0
- package/src/theme/theme-context.tsx +15 -1
- package/src/tickers/instrument-kind.ts +9 -1
- package/src/tickers/listing-name.ts +34 -0
- package/src/tickers/listing-venues.ts +154 -0
- package/src/tickers/open-target.ts +11 -3
- package/src/tickers/perpetual-listing.ts +151 -0
- package/src/tickers/prediction-listing.ts +26 -0
- package/src/tickers/search/index.ts +34 -6
- package/src/tickers/search/ranking.ts +85 -4
- package/src/tickers/ticker-changes.ts +213 -0
- package/src/time-series/chart-data.ts +2 -0
- package/src/time-series/economic.ts +2 -6
- package/src/time-series/ice-credit.ts +39 -0
- package/src/time-series/parsed-history-cache.ts +41 -11
- package/src/time-series/resolve.ts +163 -28
- package/src/time-series/studies.ts +1 -0
- package/src/time-series/types.ts +8 -0
- package/src/types/config.ts +4 -2
- package/src/types/data-provider.ts +19 -1
- package/src/types/financials.ts +23 -0
- package/src/types/headless.ts +74 -0
- package/src/types/instrument.ts +4 -0
- package/src/types/plugin.ts +60 -2
- package/src/types/price-history.ts +2 -0
- package/src/types/ticker-changes.ts +26 -0
- package/src/ui/context-menu.tsx +13 -1
- package/src/ui/host.tsx +49 -7
- package/src/ui/live-resize.ts +10 -0
- package/src/ui/live-stretch.ts +51 -19
- package/src/ui/sticky-scroll.ts +7 -0
- package/src/utils/central-banks.ts +76 -0
- package/src/utils/cli-output.ts +126 -16
- package/src/utils/crypto-pair.ts +1 -1
- package/src/utils/currency-pair.ts +66 -0
- package/src/utils/currency-units.ts +11 -0
- package/src/utils/datetime-format.ts +27 -6
- package/src/utils/decimal-comma.ts +57 -0
- package/src/utils/dom-screenshot.ts +3 -1
- package/src/utils/double-escape-close.ts +15 -1
- package/src/utils/exchanges.ts +36 -0
- package/src/utils/format.ts +19 -2
- package/src/utils/forward-dividend.ts +14 -0
- package/src/utils/fx-status.ts +6 -1
- package/src/utils/guards.ts +25 -0
- package/src/utils/inline-content-tokenizer.ts +22 -3
- package/src/utils/local-utc-offset.ts +37 -0
- package/src/utils/market-capitalization.ts +8 -0
- package/src/utils/one-shot.ts +73 -0
- package/src/utils/options.ts +37 -8
- package/src/utils/plugin-proxy-hosts.json +8 -1
- package/src/utils/utc-time.ts +12 -0
- package/src/plugins/builtin/credit-boards/pane.tsx +0 -30
- package/src/ui/pane-fill.ts +0 -11
- /package/src/plugins/{builtin/plugin-marketplace → marketplace}/activation.ts +0 -0
- /package/src/plugins/{builtin/plugin-marketplace → marketplace}/ids.ts +0 -0
- /package/src/plugins/{builtin/plugin-marketplace → marketplace}/packs.ts +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { FINANCIAL_VINTAGE_NOTICE, SEC_EPS_BASIS_NOTICE } from "../../../utils/financial-statements";
|
|
2
|
+
import { usePaneSharePreparation } from "../../../shares/prepare";
|
|
2
3
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
3
4
|
import { Box, useUiCapabilities } from "../../../ui";
|
|
4
5
|
import {
|
|
@@ -43,7 +44,7 @@ import {
|
|
|
43
44
|
type AppState,
|
|
44
45
|
} from "../../../state/app/context";
|
|
45
46
|
import { colors } from "../../../theme/colors";
|
|
46
|
-
import { isUsListingExchange, parsePublicTickerKey, publicTickerKey
|
|
47
|
+
import { isUsListingExchange, parsePublicTickerKey, publicTickerKey } from "../../../utils/exchanges";
|
|
47
48
|
import { isMarketFieldId } from "../../../time-series/field-catalog";
|
|
48
49
|
import { CHART_COMPOSER_PANE_ID } from "../../../types/config";
|
|
49
50
|
import { useRemoteUiNode } from "../../../remote/semantic-tree";
|
|
@@ -104,6 +105,7 @@ import {
|
|
|
104
105
|
} from "./settings";
|
|
105
106
|
import { resolveChartComposerShortcut } from "./shortcuts";
|
|
106
107
|
import { describeChartResolution, formatChartDateWindow, formatChartResolution } from "./viewport-labels";
|
|
108
|
+
import { intradaySessionTimeZone } from "./session-history";
|
|
107
109
|
import { ChartSeriesQuickAdd } from "./quick-add";
|
|
108
110
|
import { useLiveStreamingSetting } from "../../../state/hooks/live-streaming";
|
|
109
111
|
import { usePluginAppActions, usePluginConfigState } from "../../runtime";
|
|
@@ -116,13 +118,14 @@ import { getActiveQuoteDisplay } from "../../../market-data/market/status";
|
|
|
116
118
|
import { resolveEntryData } from "../../../market-data/selectors";
|
|
117
119
|
import { editPriceLevels, parsePriceLevels, PRICE_LEVELS_KEY, priceLevelTickerKey } from "./price-levels";
|
|
118
120
|
import { canonicalExchange } from "../../../utils/exchanges";
|
|
119
|
-
import { isPlainKey } from "../../../utils/keyboard";
|
|
120
121
|
import { resolveInstrumentForPane } from "../../../core/state/app/instrument";
|
|
121
122
|
import { CHART_FOLLOW_SERIES_SETTING_KEY, rebindFollowChartSpec, resolveFollowSeriesIds } from "./follow-binding";
|
|
122
123
|
import type { InstrumentRef } from "../../../market-data/request-types";
|
|
123
124
|
|
|
124
125
|
const RANGE_OPTIONS = RANGES.map((range, index) => ({ label: range, value: range, hint: String(index + 1) }));
|
|
125
126
|
const AUTO_VIEWPORT_DEBOUNCE_MS = 350;
|
|
127
|
+
/** A load for a moving view that has not answered in this long no longer holds the next one back. */
|
|
128
|
+
const LOAD_AHEAD_TIMEOUT_MS = 4_000;
|
|
126
129
|
/**
|
|
127
130
|
* Drawings persist into pane settings on a short debounce after the pointer
|
|
128
131
|
* settles. A share reads those settings, so it waits at least that long for a
|
|
@@ -144,6 +147,22 @@ interface RuntimeChartViewportState {
|
|
|
144
147
|
requestViewport: RuntimeChartViewport;
|
|
145
148
|
}
|
|
146
149
|
|
|
150
|
+
/** The oldest and newest market bars loaded, and whether every listing has said it keeps nothing older. */
|
|
151
|
+
function loadedMarketHistory(series: readonly ResolvedSeries[]): { start: number; end: number; complete: boolean } | null {
|
|
152
|
+
let start = Number.POSITIVE_INFINITY;
|
|
153
|
+
let end = Number.NEGATIVE_INFINITY;
|
|
154
|
+
let complete = true;
|
|
155
|
+
for (const entry of series) {
|
|
156
|
+
if (entry.observationKind !== "market" || entry.points.length === 0) continue;
|
|
157
|
+
const first = entry.points[0]!.date.getTime();
|
|
158
|
+
const last = entry.points.at(-1)!.date.getTime();
|
|
159
|
+
if (Number.isFinite(first)) start = Math.min(start, first);
|
|
160
|
+
if (Number.isFinite(last)) end = Math.max(end, last);
|
|
161
|
+
if (!entry.historyStart) complete = false;
|
|
162
|
+
}
|
|
163
|
+
return Number.isFinite(start) && Number.isFinite(end) ? { start, end, complete } : null;
|
|
164
|
+
}
|
|
165
|
+
|
|
147
166
|
function runtimeViewportFromSetting(
|
|
148
167
|
setting: ChartInteractionViewport | null,
|
|
149
168
|
authoredViewportKey: string,
|
|
@@ -258,7 +277,7 @@ function ChartComposerSurface({
|
|
|
258
277
|
}: ChartComposerSurfaceProps) {
|
|
259
278
|
const dialog = useDialog();
|
|
260
279
|
const dispatch = useAppDispatch();
|
|
261
|
-
const {
|
|
280
|
+
const { cellWidthPx = 8 } = useUiCapabilities();
|
|
262
281
|
const desktopWeb = useUiCapabilities().nativePaneChrome === true;
|
|
263
282
|
const paneId = usePaneInstanceId();
|
|
264
283
|
const liveStreaming = useLiveStreamingSetting();
|
|
@@ -351,9 +370,15 @@ function ChartComposerSurface({
|
|
|
351
370
|
spec.viewport.range,
|
|
352
371
|
spec.viewport.resolution,
|
|
353
372
|
]);
|
|
373
|
+
// Auto names the bars it is on, which change as the view moves: a pan back
|
|
374
|
+
// past where a source keeps 30-minute bars charts days instead.
|
|
375
|
+
const autoBars = spec.viewport.resolution === "auto" ? resolution.resolution ?? null : null;
|
|
354
376
|
const resolutionOptions = useMemo(
|
|
355
|
-
() => availableResolutions.map((value) => ({
|
|
356
|
-
|
|
377
|
+
() => availableResolutions.map((value) => ({
|
|
378
|
+
label: value === "auto" && autoBars ? `Auto (${formatChartResolution(autoBars)})` : formatChartResolution(value),
|
|
379
|
+
value,
|
|
380
|
+
})),
|
|
381
|
+
[autoBars, availableResolutions],
|
|
357
382
|
);
|
|
358
383
|
const selectedStudies = getSelectedBuiltinStudies(spec);
|
|
359
384
|
const selectedPairStudies = getSelectedPairStudies(spec);
|
|
@@ -396,7 +421,7 @@ function ChartComposerSurface({
|
|
|
396
421
|
),
|
|
397
422
|
[resolution.bufferedSeries, resolution.legendSeries, resolution.series, spec],
|
|
398
423
|
);
|
|
399
|
-
const {
|
|
424
|
+
const { notify } = usePluginAppActions();
|
|
400
425
|
const { runtime } = usePluginRenderContext();
|
|
401
426
|
const [levelStore, setLevelStore] = usePluginConfigState<unknown>(PRICE_LEVELS_KEY, null);
|
|
402
427
|
const alertsJson = useAppSelector((state) => state.config.pluginConfig[PRICE_ALERTS_STORE.pluginId]?.[PRICE_ALERTS_STORE.key]);
|
|
@@ -472,10 +497,6 @@ function ChartComposerSurface({
|
|
|
472
497
|
...(alertsOn ? { action: { label: "alert", title: "Alert at Level", run: (level) => { void alertAtLevel(level.value); } } } : {}),
|
|
473
498
|
};
|
|
474
499
|
}, [alertAtLevel, alertsJson, alertsOn, editLevels, levelStore, listing]);
|
|
475
|
-
const shareTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
476
|
-
useEffect(() => () => {
|
|
477
|
-
if (shareTimerRef.current !== null) clearTimeout(shareTimerRef.current);
|
|
478
|
-
}, []);
|
|
479
500
|
const [interactionCaptured, setInteractionCapturedState] = useState(false);
|
|
480
501
|
// Typing in quick-add must not freeze the plot: it only takes the keyboard.
|
|
481
502
|
const [modalCaptured, setModalCaptured] = useState(false);
|
|
@@ -631,7 +652,19 @@ function ChartComposerSurface({
|
|
|
631
652
|
const activatePane = useCallback(() => {
|
|
632
653
|
if (!focused) dispatch({ type: "FOCUS_PANE", paneId });
|
|
633
654
|
}, [dispatch, focused, paneId]);
|
|
655
|
+
useEffect(() => () => {
|
|
656
|
+
if (runtimeViewportTimerRef.current !== null) {
|
|
657
|
+
clearTimeout(runtimeViewportTimerRef.current);
|
|
658
|
+
runtimeViewportTimerRef.current = null;
|
|
659
|
+
}
|
|
660
|
+
}, []);
|
|
661
|
+
// The view this pane last saved, so its own write coming back through the
|
|
662
|
+
// settings is not mistaken for another device's view: that would cancel the
|
|
663
|
+
// load a pan still in progress has scheduled and put its window back.
|
|
664
|
+
const savedInteractionViewportRef = useRef<string | null>(null);
|
|
634
665
|
useEffect(() => {
|
|
666
|
+
if (persistedInteractionViewport && requestViewportOwnerRef.current === authoredViewportKey
|
|
667
|
+
&& JSON.stringify(persistedInteractionViewport) === savedInteractionViewportRef.current) return;
|
|
635
668
|
if (runtimeViewportTimerRef.current !== null) {
|
|
636
669
|
clearTimeout(runtimeViewportTimerRef.current);
|
|
637
670
|
runtimeViewportTimerRef.current = null;
|
|
@@ -645,30 +678,41 @@ function ChartComposerSurface({
|
|
|
645
678
|
requestViewportOwnerRef.current = authoredViewportKey;
|
|
646
679
|
setRuntimeViewportState((current) => current?.key === authoredViewportKey ? current : restored);
|
|
647
680
|
if (persistedInteractionViewport && !restored) setStoredInteractionViewport(null);
|
|
648
|
-
return () => {
|
|
649
|
-
if (runtimeViewportTimerRef.current !== null) {
|
|
650
|
-
clearTimeout(runtimeViewportTimerRef.current);
|
|
651
|
-
runtimeViewportTimerRef.current = null;
|
|
652
|
-
}
|
|
653
|
-
};
|
|
654
681
|
}, [authoredViewportKey, persistedInteractionViewport, setStoredInteractionViewport]);
|
|
655
|
-
|
|
682
|
+
// The bars loaded so far, and whether the source has said nothing older exists.
|
|
683
|
+
const loadedHistory = useMemo(() => loadedMarketHistory(plottedSeries), [plottedSeries]);
|
|
684
|
+
const loadedHistoryRef = useRef(loadedHistory);
|
|
685
|
+
loadedHistoryRef.current = loadedHistory;
|
|
686
|
+
// The newest bar seen at all: bars loaded for a moved view (finer ones, after
|
|
687
|
+
// a zoom) can end before it, and a pan forward then has more to ask for.
|
|
688
|
+
const newestBarRef = useRef(Number.NEGATIVE_INFINITY);
|
|
689
|
+
if (loadedHistory) newestBarRef.current = Math.max(newestBarRef.current, loadedHistory.end);
|
|
690
|
+
// A window asked for and not answered yet: the result's view ends where the request does once it lands.
|
|
691
|
+
const loadingWindowRef = useRef<{ end: number; at: number } | null>(null);
|
|
692
|
+
const resultViewportEnd = resolution.viewport?.end.getTime() ?? null;
|
|
693
|
+
if (loadingWindowRef.current && resultViewportEnd !== null
|
|
694
|
+
&& Math.abs(resultViewportEnd - loadingWindowRef.current.end) < 1_000) loadingWindowRef.current = null;
|
|
695
|
+
const commitRuntimeViewport = useCallback((save = true) => {
|
|
656
696
|
const requestViewport = requestViewportRef.current;
|
|
657
697
|
if (!requestViewport) return;
|
|
658
698
|
const adaptiveViewport = spec.viewport.resolution === "auto"
|
|
659
699
|
? adaptiveViewportRef.current
|
|
660
700
|
: null;
|
|
701
|
+
loadingWindowRef.current = { end: requestViewport.end.getTime(), at: Date.now() };
|
|
661
702
|
setRuntimeViewportState({
|
|
662
703
|
key: authoredViewportKey,
|
|
663
704
|
adaptiveViewport,
|
|
664
705
|
requestViewport,
|
|
665
706
|
});
|
|
666
|
-
|
|
707
|
+
if (!save) return;
|
|
708
|
+
const saved = {
|
|
667
709
|
authoredViewportKey,
|
|
668
710
|
start: requestViewport.start.toISOString(),
|
|
669
711
|
end: requestViewport.end.toISOString(),
|
|
670
712
|
adaptive: adaptiveViewport !== null,
|
|
671
|
-
} satisfies ChartInteractionViewport
|
|
713
|
+
} satisfies ChartInteractionViewport;
|
|
714
|
+
savedInteractionViewportRef.current = JSON.stringify(parseChartInteractionViewport(saved));
|
|
715
|
+
setStoredInteractionViewport(saved);
|
|
672
716
|
}, [authoredViewportKey, setStoredInteractionViewport, spec.viewport.resolution]);
|
|
673
717
|
const handleChartViewportChange = useCallback((
|
|
674
718
|
next: { start: Date; end: Date } | null,
|
|
@@ -681,6 +725,7 @@ function ChartComposerSurface({
|
|
|
681
725
|
if (!next) {
|
|
682
726
|
adaptiveViewportRef.current = null;
|
|
683
727
|
requestViewportRef.current = null;
|
|
728
|
+
loadingWindowRef.current = null;
|
|
684
729
|
setRuntimeViewportState(null);
|
|
685
730
|
setStoredInteractionViewport(null);
|
|
686
731
|
return;
|
|
@@ -694,24 +739,31 @@ function ChartComposerSurface({
|
|
|
694
739
|
// A pan can leave the window a provider serves at the current resolution
|
|
695
740
|
// just as a zoom can, so both re-pick.
|
|
696
741
|
if (spec.viewport.resolution === "auto") adaptiveViewportRef.current = viewport;
|
|
742
|
+
// Bars are asked for while the view is still moving, once it comes within
|
|
743
|
+
// half a screen of the oldest loaded one (or of the newest, when newer
|
|
744
|
+
// ones exist), so a long pan keeps going instead of running into the end
|
|
745
|
+
// of what is loaded and waiting for the pointer to rest.
|
|
746
|
+
const loaded = loadedHistoryRef.current;
|
|
747
|
+
const loading = loadingWindowRef.current;
|
|
748
|
+
const reach = (end - start) / 2;
|
|
749
|
+
const nearOldest = !!loaded && !loaded.complete && start - loaded.start < reach;
|
|
750
|
+
const nearNewest = !!loaded && loaded.end < newestBarRef.current - reach / 10 && loaded.end - end < reach;
|
|
751
|
+
if ((nearOldest || nearNewest) && (!loading || Date.now() - loading.at > LOAD_AHEAD_TIMEOUT_MS)) {
|
|
752
|
+
commitRuntimeViewport(false);
|
|
753
|
+
}
|
|
697
754
|
runtimeViewportTimerRef.current = globalThis.setTimeout(() => {
|
|
698
755
|
runtimeViewportTimerRef.current = null;
|
|
699
756
|
commitRuntimeViewport();
|
|
700
757
|
}, AUTO_VIEWPORT_DEBOUNCE_MS);
|
|
701
|
-
}, [authoredViewportKey, commitRuntimeViewport, spec.viewport.resolution]);
|
|
702
|
-
|
|
703
|
-
// The share reads pane settings, so the gesture in flight lands there first.
|
|
758
|
+
}, [authoredViewportKey, commitRuntimeViewport, setStoredInteractionViewport, spec.viewport.resolution]);
|
|
759
|
+
usePaneSharePreparation(paneId, async () => {
|
|
704
760
|
if (runtimeViewportTimerRef.current !== null) {
|
|
705
761
|
clearTimeout(runtimeViewportTimerRef.current);
|
|
706
762
|
runtimeViewportTimerRef.current = null;
|
|
707
763
|
commitRuntimeViewport();
|
|
708
764
|
}
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
shareTimerRef.current = null;
|
|
712
|
-
sharePane(paneId);
|
|
713
|
-
}, SHARE_SETTLE_DELAY_MS);
|
|
714
|
-
}, [commitRuntimeViewport, paneId, sharePane]);
|
|
765
|
+
await new Promise((resolve) => setTimeout(resolve, SHARE_SETTLE_DELAY_MS));
|
|
766
|
+
});
|
|
715
767
|
|
|
716
768
|
useRemoteUiNode({
|
|
717
769
|
role: "chart-data",
|
|
@@ -800,12 +852,6 @@ function ChartComposerSurface({
|
|
|
800
852
|
);
|
|
801
853
|
useShortcut((event) => {
|
|
802
854
|
if (interactionCaptureRef.current || dialogOpen) return;
|
|
803
|
-
if (publicSharing && isPlainKey(event, "y")) {
|
|
804
|
-
event.preventDefault();
|
|
805
|
-
event.stopPropagation();
|
|
806
|
-
shareChart();
|
|
807
|
-
return;
|
|
808
|
-
}
|
|
809
855
|
const shortcut = resolveChartComposerShortcut(event, RANGES.length);
|
|
810
856
|
if (!shortcut) return;
|
|
811
857
|
event.preventDefault();
|
|
@@ -871,11 +917,10 @@ function ChartComposerSurface({
|
|
|
871
917
|
});
|
|
872
918
|
|
|
873
919
|
// Footer registrations compare presentation, so their callbacks must read current actions.
|
|
874
|
-
const currentActionsRef = useRef({ openSeriesEditor, openResolutionPicker
|
|
875
|
-
currentActionsRef.current = { openSeriesEditor, openResolutionPicker
|
|
920
|
+
const currentActionsRef = useRef({ openSeriesEditor, openResolutionPicker });
|
|
921
|
+
currentActionsRef.current = { openSeriesEditor, openResolutionPicker };
|
|
876
922
|
const footerSeries = useCallback(() => { void currentActionsRef.current.openSeriesEditor(); }, []);
|
|
877
923
|
const footerResolution = useCallback(() => { void currentActionsRef.current.openResolutionPicker(); }, []);
|
|
878
|
-
const footerShare = useCallback(() => { currentActionsRef.current.shareChart(); }, []);
|
|
879
924
|
const openIndicators = useCallback((event?: PaneFooterPressEvent) => {
|
|
880
925
|
indicatorsDialogRef.current?.open(footerAnchorPoint(event));
|
|
881
926
|
}, []);
|
|
@@ -901,9 +946,8 @@ function ChartComposerSurface({
|
|
|
901
946
|
{ id: "formulas", key: "f", label: "ormulas", onPress: openFormulas, disabled: formulasDisabled },
|
|
902
947
|
{ id: "resolution", key: "t", label: "imeframe", onPress: footerResolution },
|
|
903
948
|
...(anchorable ? [{ id: "vwap-anchor", key: "v", label: "wap anchor", title: "Anchor VWAP", onPress: footerAnchor }] : []),
|
|
904
|
-
...(publicSharing ? [{ id: "share", key: "y", label: " share", onPress: footerShare }] : []),
|
|
905
949
|
],
|
|
906
|
-
}), [resolution.loading, pickingAnchor, footerSeries, openIndicators, indicatorsDisabled, openFormulas, formulasDisabled, footerResolution, anchorable, footerAnchor
|
|
950
|
+
}), [resolution.loading, pickingAnchor, footerSeries, openIndicators, indicatorsDisabled, openFormulas, formulasDisabled, footerResolution, anchorable, footerAnchor]);
|
|
907
951
|
|
|
908
952
|
// A fixed window (a GIP session) highlights no range, so the bar names it.
|
|
909
953
|
const dateWindowLabel = useMemo(() => {
|
|
@@ -911,7 +955,7 @@ function ChartComposerSurface({
|
|
|
911
955
|
if (!window) return undefined;
|
|
912
956
|
const exchange = spec.series.find((entry) => entry.source.kind === "security")?.source;
|
|
913
957
|
const timeZone = exchange?.kind === "security"
|
|
914
|
-
?
|
|
958
|
+
? intradaySessionTimeZone(exchange.instrument.symbol, exchange.instrument.exchange)
|
|
915
959
|
: "UTC";
|
|
916
960
|
return formatChartDateWindow(window, timeZone);
|
|
917
961
|
}, [spec.series, spec.viewport.dateWindow]);
|
|
@@ -7,7 +7,8 @@ import {
|
|
|
7
7
|
type ChartResolutionSupport,
|
|
8
8
|
type ManualChartResolution,
|
|
9
9
|
} from "../../../time-series/resolution";
|
|
10
|
-
import { resolveExchangeTimeZone } from "../../../utils/exchanges";
|
|
10
|
+
import { parsePublicTickerKey, resolveExchangeTimeZone } from "../../../utils/exchanges";
|
|
11
|
+
import { listingSuffixExchange } from "../../../sources/listing-symbols";
|
|
11
12
|
import { getPricePointTimestamp } from "../../../utils/price-history";
|
|
12
13
|
import { pricePointIntegrity } from "../../../utils/price-history-integrity";
|
|
13
14
|
import { zonedDateKey, zonedWallClockToUtcMs } from "../../../utils/zoned-date-time";
|
|
@@ -98,6 +99,20 @@ function sessionUtcBounds(value: string, timeZone: string): {
|
|
|
98
99
|
};
|
|
99
100
|
}
|
|
100
101
|
|
|
102
|
+
/**
|
|
103
|
+
* The zone a listing's sessions are dated in: its exchange's, else the one its
|
|
104
|
+
* key or listing suffix names (RMS.AX trades on the ASX). A session is the
|
|
105
|
+
* bars of one local day, so it starts at the local open even where that falls
|
|
106
|
+
* before UTC midnight (10:00 in Sydney is 23:00 UTC the day before). UTC for a
|
|
107
|
+
* listing without a known venue, such as a bare US symbol.
|
|
108
|
+
*/
|
|
109
|
+
export function intradaySessionTimeZone(symbol: string, exchange: string | undefined): string {
|
|
110
|
+
const parsed = parsePublicTickerKey(symbol);
|
|
111
|
+
return resolveExchangeTimeZone(exchange)
|
|
112
|
+
?? resolveExchangeTimeZone(parsed.exchange ?? listingSuffixExchange(parsed.symbol))
|
|
113
|
+
?? "UTC";
|
|
114
|
+
}
|
|
115
|
+
|
|
101
116
|
function normalizedPoints(points: readonly PricePoint[]): PricePoint[] {
|
|
102
117
|
const byTimestamp = new Map<number, PricePoint>();
|
|
103
118
|
for (const point of points) {
|
|
@@ -232,11 +247,11 @@ async function loadHistoricalFallback(
|
|
|
232
247
|
exchange: string,
|
|
233
248
|
request: IntradayRequest,
|
|
234
249
|
now: Date,
|
|
250
|
+
timeZone: string,
|
|
235
251
|
context?: MarketDataRequestContext,
|
|
236
252
|
): Promise<PriceHistoryResult> {
|
|
237
253
|
const empty = { points: [], resolution: request.resolution };
|
|
238
254
|
if (request.session) {
|
|
239
|
-
const timeZone = resolveExchangeTimeZone(exchange) ?? "UTC";
|
|
240
255
|
const bounds = sessionUtcBounds(request.session, timeZone);
|
|
241
256
|
return await fetchHistoryResult(provider, symbol, exchange,
|
|
242
257
|
{ kind: "detail", start: bounds.start, end: bounds.end, interval: request.resolution }, context).catch(() => null) ?? empty;
|
|
@@ -256,14 +271,14 @@ export async function loadIntradayWindow(options: {
|
|
|
256
271
|
now?: Date;
|
|
257
272
|
context?: MarketDataRequestContext;
|
|
258
273
|
}): Promise<LoadedIntradayWindow> {
|
|
259
|
-
const timeZone =
|
|
274
|
+
const timeZone = intradaySessionTimeZone(options.symbol, options.exchange);
|
|
260
275
|
let acquisition = options.request.session
|
|
261
276
|
? await loadHistoricalFallback(
|
|
262
277
|
options.provider,
|
|
263
278
|
options.symbol,
|
|
264
279
|
options.exchange,
|
|
265
280
|
options.request,
|
|
266
|
-
options.now ?? new Date(), options.context,
|
|
281
|
+
options.now ?? new Date(), timeZone, options.context,
|
|
267
282
|
)
|
|
268
283
|
: await loadTrailingHistory(
|
|
269
284
|
options.provider,
|
|
@@ -292,7 +307,7 @@ export async function loadIntradayWindow(options: {
|
|
|
292
307
|
options.symbol,
|
|
293
308
|
options.exchange,
|
|
294
309
|
options.request,
|
|
295
|
-
options.now ?? new Date(), options.context,
|
|
310
|
+
options.now ?? new Date(), timeZone, options.context,
|
|
296
311
|
);
|
|
297
312
|
raw = acquisition.points;
|
|
298
313
|
window = resolveIntradaySessionWindow(raw, {
|
|
@@ -17,10 +17,11 @@ import { requestChatPaneAction } from "./pane-requests";
|
|
|
17
17
|
|
|
18
18
|
const CHAT_PANE_TEMPLATE_ID = "new-chat-pane";
|
|
19
19
|
/**
|
|
20
|
-
* Pane template value
|
|
21
|
-
* open
|
|
20
|
+
* Pane template value, for a template opened with no conversation: leave the
|
|
21
|
+
* open Chat pane on the conversation it shows instead of switching it to the
|
|
22
|
+
* one the bar would open.
|
|
22
23
|
*/
|
|
23
|
-
export const
|
|
24
|
+
export const CHAT_KEEP_CONVERSATION_VALUE = "keepConversation";
|
|
24
25
|
const CHAT_SEARCH_PROVIDER_ID = "chat:conversations";
|
|
25
26
|
|
|
26
27
|
type OpenChatPane = Pick<GloomPluginContext, "createPaneFromTemplate">;
|
|
@@ -31,16 +32,13 @@ type OpenChatPane = Pick<GloomPluginContext, "createPaneFromTemplate">;
|
|
|
31
32
|
*/
|
|
32
33
|
export function openChatConversation(ctx: OpenChatPane, channelId: string): void {
|
|
33
34
|
requestChatPaneAction({ action: "compose", channelId });
|
|
34
|
-
ctx.createPaneFromTemplate(CHAT_PANE_TEMPLATE_ID, {
|
|
35
|
-
arg: channelId,
|
|
36
|
-
values: { [CHAT_REUSE_PANE_VALUE]: "1" },
|
|
37
|
-
});
|
|
35
|
+
ctx.createPaneFromTemplate(CHAT_PANE_TEMPLATE_ID, { arg: channelId });
|
|
38
36
|
}
|
|
39
37
|
|
|
40
38
|
/** The Chat pane's own New DM dialog, in the open Chat pane or a new one. */
|
|
41
39
|
export function openChatNewDm(ctx: OpenChatPane): void {
|
|
42
40
|
requestChatPaneAction({ action: "new-dm" });
|
|
43
|
-
ctx.createPaneFromTemplate(CHAT_PANE_TEMPLATE_ID, { values: { [
|
|
41
|
+
ctx.createPaneFromTemplate(CHAT_PANE_TEMPLATE_ID, { values: { [CHAT_KEEP_CONVERSATION_VALUE]: "1" } });
|
|
44
42
|
}
|
|
45
43
|
|
|
46
44
|
const BADGES: Record<ChatConversationKind, string> = {
|
|
@@ -11,6 +11,8 @@ import type { ChatContentController } from "./types";
|
|
|
11
11
|
import { getComposerCursorOffset, moveComposerCursorToOffset } from "./composer-cursor";
|
|
12
12
|
import { insertedText, pastedImagePaths } from "../attachments/transfer";
|
|
13
13
|
import { chatTextWithImages } from "../attachments/model";
|
|
14
|
+
import { isManagedBot } from "../ghost-user";
|
|
15
|
+
import { CHAT_PERSON_ICON_WIDTH } from "../people";
|
|
14
16
|
|
|
15
17
|
interface MutableRef<T> {
|
|
16
18
|
current: T;
|
|
@@ -398,7 +400,10 @@ export function useChatComposerRuntime({
|
|
|
398
400
|
const replyPreview = replyTo
|
|
399
401
|
? formatInlinePreview(
|
|
400
402
|
chatTextWithImages(replyTo.content, replyTo.attachments?.length ?? 0),
|
|
401
|
-
Math.max(
|
|
403
|
+
Math.max(
|
|
404
|
+
contentWidth - ` replying to @${replyTo.user.username}`.length - (isManagedBot(replyTo.user) ? CHAT_PERSON_ICON_WIDTH + 1 : 2) - COMPOSER_ACTION_WIDTH - 1,
|
|
405
|
+
0,
|
|
406
|
+
),
|
|
402
407
|
)
|
|
403
408
|
: "";
|
|
404
409
|
const editingPreview = editingMessage
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
1
2
|
import { Box, Text, TextAttributes, useCommandBarShortcut, type TextareaRenderable } from "../../../../ui";
|
|
2
3
|
import { getMessageComposerBlockHeight, MessageComposer } from "../../../../components/ui";
|
|
3
4
|
import { colors } from "../../../../theme/colors";
|
|
@@ -7,6 +8,8 @@ import type { ChatMessage } from "../../../../api-client";
|
|
|
7
8
|
import { InlineAuthActions } from "../../cloud/auth-actions";
|
|
8
9
|
import { Button, ListView } from "../../../../components/ui";
|
|
9
10
|
import { COMPOSER_ACTION_WIDTH } from "../layout";
|
|
11
|
+
import { isManagedBot } from "../ghost-user";
|
|
12
|
+
import { ChatBotIcon } from "../message/person-icons";
|
|
10
13
|
import type { ChatMentionSuggestion } from "./mentions";
|
|
11
14
|
import type { ChatDraftAttachment } from "../controller/attachments";
|
|
12
15
|
import { DesktopChatAttachButton, DesktopChatAttachmentStrip } from "../attachments/desktop";
|
|
@@ -20,6 +23,8 @@ interface MutableRef<T> {
|
|
|
20
23
|
}
|
|
21
24
|
|
|
22
25
|
interface ChatComposerAreaProps {
|
|
26
|
+
/** The first-chat handle prompt, drawn above everything else once you can send. */
|
|
27
|
+
handlePrompt?: ReactNode;
|
|
23
28
|
canSend: boolean;
|
|
24
29
|
cancelEditMessage: () => void;
|
|
25
30
|
clearReplyTarget: () => void;
|
|
@@ -85,6 +90,7 @@ function ChatMentionSuggestions({
|
|
|
85
90
|
}
|
|
86
91
|
|
|
87
92
|
export function ChatComposerArea({
|
|
93
|
+
handlePrompt,
|
|
88
94
|
canSend,
|
|
89
95
|
cancelEditMessage,
|
|
90
96
|
clearReplyTarget,
|
|
@@ -159,6 +165,8 @@ export function ChatComposerArea({
|
|
|
159
165
|
/>
|
|
160
166
|
)}
|
|
161
167
|
|
|
168
|
+
{handlePrompt}
|
|
169
|
+
|
|
162
170
|
{editingMessage && (
|
|
163
171
|
<Box height={1} width={contentWidth} flexDirection="row">
|
|
164
172
|
<Text fg={colors.textMuted}>{` ${t("editing")} `}</Text>
|
|
@@ -176,7 +184,9 @@ export function ChatComposerArea({
|
|
|
176
184
|
<Box height={1} width={contentWidth} flexDirection="row">
|
|
177
185
|
<Text fg={colors.textMuted}>{` ${t("replying to")} `}</Text>
|
|
178
186
|
<Text fg={colors.positive} attributes={TextAttributes.BOLD}>{`@${replyTo.user.username}`}</Text>
|
|
179
|
-
|
|
187
|
+
{isManagedBot(replyTo.user) && <ChatBotIcon />}
|
|
188
|
+
{/* The bot's icon stands where the colon would. */}
|
|
189
|
+
<Text fg={colors.textDim}>{replyPreview ? `${isManagedBot(replyTo.user) ? " " : ": "}${replyPreview}` : ""}</Text>
|
|
180
190
|
<Box flexGrow={1} />
|
|
181
191
|
<Button stopPropagation
|
|
182
192
|
label={t("Cancel")}
|
|
@@ -251,6 +261,7 @@ export function getChatComposerAreaHeight({
|
|
|
251
261
|
replyTo,
|
|
252
262
|
mentionSuggestionCount,
|
|
253
263
|
draftAttachmentCount = 0,
|
|
264
|
+
promptRows = 0,
|
|
254
265
|
}: {
|
|
255
266
|
canSend: boolean;
|
|
256
267
|
composerHeight: number;
|
|
@@ -260,9 +271,11 @@ export function getChatComposerAreaHeight({
|
|
|
260
271
|
mentionSuggestionCount?: number;
|
|
261
272
|
/** The terminal draws a row per waiting image; the desktop strip sizes itself. */
|
|
262
273
|
draftAttachmentCount?: number;
|
|
274
|
+
/** Terminal rows the handle prompt above the composer takes. */
|
|
275
|
+
promptRows?: number;
|
|
263
276
|
}) {
|
|
264
277
|
if (!canSend) return 2;
|
|
265
|
-
return getMessageComposerBlockHeight({ height: composerHeight, nativePaneChrome })
|
|
278
|
+
return promptRows + getMessageComposerBlockHeight({ height: composerHeight, nativePaneChrome })
|
|
266
279
|
+ (editingMessage || replyTo ? 1 : 0)
|
|
267
280
|
+ Math.max(0, mentionSuggestionCount ?? 0)
|
|
268
281
|
+ (!nativePaneChrome && !editingMessage ? draftAttachmentCount : 0);
|
|
@@ -8,7 +8,9 @@ import { useRendererHost, useUiCapabilities } from "../../../../ui";
|
|
|
8
8
|
import { useOptionalDialog, type PromptContext } from "../../../../ui/dialog";
|
|
9
9
|
import { chatAuthorName, isDiscordGhost } from "../ghost-user";
|
|
10
10
|
import { chatMessageOpenTargets, type ChatOpenTarget } from "./open-targets";
|
|
11
|
+
import { chatMessagePaneLinks, type ChatMessagePaneLink } from "../pane-links/model";
|
|
11
12
|
import { openChatImageViewer } from "../attachments/desktop";
|
|
13
|
+
import { canReactToMessage } from "../reactions";
|
|
12
14
|
|
|
13
15
|
/**
|
|
14
16
|
* The chat pane's keys, shown in its footer and listed in its pane menu. The
|
|
@@ -27,6 +29,7 @@ export function useChatFooter({
|
|
|
27
29
|
focusComposer,
|
|
28
30
|
catalog,
|
|
29
31
|
openTicker,
|
|
32
|
+
openPaneLink,
|
|
30
33
|
openAttachPicker,
|
|
31
34
|
profilePopoverUser,
|
|
32
35
|
showProfilePopover,
|
|
@@ -45,6 +48,8 @@ export function useChatFooter({
|
|
|
45
48
|
needsProfileSetup,
|
|
46
49
|
openProfileSetup,
|
|
47
50
|
authorMessageAction,
|
|
51
|
+
reactionsEnabled = false,
|
|
52
|
+
openReactionPicker,
|
|
48
53
|
}: {
|
|
49
54
|
/**
|
|
50
55
|
* The composer or the New DM overlay owns the keyboard. Hints about the
|
|
@@ -62,6 +67,8 @@ export function useChatFooter({
|
|
|
62
67
|
focusComposer: () => void;
|
|
63
68
|
catalog: Record<string, InlineTickerCatalogEntry>;
|
|
64
69
|
openTicker: (symbol: string) => void;
|
|
70
|
+
/** Opens what a message's chip stands for. */
|
|
71
|
+
openPaneLink: (link: ChatMessagePaneLink) => void;
|
|
65
72
|
/** Opens the composer's file picker; null where images cannot be attached. */
|
|
66
73
|
openAttachPicker: (() => void) | null;
|
|
67
74
|
profilePopoverUser: ChatUserSummary | null;
|
|
@@ -84,18 +91,26 @@ export function useChatFooter({
|
|
|
84
91
|
openProfileSetup: () => void;
|
|
85
92
|
/** "Message @author" for the selected message, where its author can be written to. */
|
|
86
93
|
authorMessageAction: { label: string; run: () => void } | null;
|
|
94
|
+
/** The server takes reactions and you can send. */
|
|
95
|
+
reactionsEnabled?: boolean;
|
|
96
|
+
/** Opens the reaction picker for the message at an index. */
|
|
97
|
+
openReactionPicker?: (index: number) => void;
|
|
87
98
|
}) {
|
|
88
99
|
const dialog = useOptionalDialog();
|
|
89
100
|
const rendererHost = useRendererHost();
|
|
90
|
-
const content = selectedMessage
|
|
101
|
+
const { links: paneLinks, content } = chatMessagePaneLinks(selectedMessage);
|
|
91
102
|
const attachments = selectedMessage?.attachments;
|
|
92
103
|
const openTargets = useMemo(
|
|
93
|
-
() => chatMessageOpenTargets(content, catalog, attachments),
|
|
94
|
-
[attachments, catalog, content],
|
|
104
|
+
() => chatMessageOpenTargets(content, catalog, attachments, paneLinks),
|
|
105
|
+
[attachments, catalog, content, paneLinks],
|
|
95
106
|
);
|
|
96
107
|
const { nativePaneChrome } = useUiCapabilities();
|
|
97
108
|
|
|
98
109
|
const openTarget = useCallback((target: ChatOpenTarget) => {
|
|
110
|
+
if (target.kind === "pane") {
|
|
111
|
+
openPaneLink(target.link);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
99
114
|
if (target.kind === "ticker") {
|
|
100
115
|
openTicker(target.symbol);
|
|
101
116
|
return;
|
|
@@ -111,7 +126,7 @@ export function useChatFooter({
|
|
|
111
126
|
return;
|
|
112
127
|
}
|
|
113
128
|
void rendererHost.openExternal(target.url);
|
|
114
|
-
}, [dialog, nativePaneChrome, openTicker, rendererHost, selectedMessage]);
|
|
129
|
+
}, [dialog, nativePaneChrome, openPaneLink, openTicker, rendererHost, selectedMessage]);
|
|
115
130
|
|
|
116
131
|
// One target opens at once; several ask which, in the order the message reads.
|
|
117
132
|
const openSelectedTargets = useCallback(async () => {
|
|
@@ -157,12 +172,15 @@ export function useChatFooter({
|
|
|
157
172
|
}, [closeProfilePopover, selectedIdx]);
|
|
158
173
|
|
|
159
174
|
const canEdit = canSend && !!selectedMessage && selectedMessage.id === latestEditableMessageId;
|
|
175
|
+
const canReact = reactionsEnabled && !!openReactionPicker && !!selectedMessage && canReactToMessage(selectedMessage);
|
|
160
176
|
const replyToId = selectedMessage?.replyToId ?? null;
|
|
161
177
|
const onlyTarget = openTargets.length === 1 ? openTargets[0]! : null;
|
|
162
178
|
const failedSend = selectedMessage?.clientStatus === "failed";
|
|
163
179
|
const canAttachImages = !!openAttachPicker;
|
|
164
180
|
const openTargetTitle = onlyTarget
|
|
165
|
-
? onlyTarget.kind === "ticker"
|
|
181
|
+
? onlyTarget.kind === "ticker"
|
|
182
|
+
? `Open $${onlyTarget.symbol}`
|
|
183
|
+
: onlyTarget.kind === "image" ? "Open Image" : onlyTarget.kind === "pane" ? "Open Pane" : "Open Link"
|
|
166
184
|
: openTargets.every((target) => target.kind === "ticker")
|
|
167
185
|
? "Open Ticker…"
|
|
168
186
|
: openTargets.every((target) => target.kind === "link")
|
|
@@ -188,6 +206,7 @@ export function useChatFooter({
|
|
|
188
206
|
setChannelNotificationsEnabled,
|
|
189
207
|
toggleAuthorProfile,
|
|
190
208
|
authorMessageAction,
|
|
209
|
+
openReactionPicker,
|
|
191
210
|
});
|
|
192
211
|
latest.current = {
|
|
193
212
|
beginEditMessage,
|
|
@@ -206,6 +225,7 @@ export function useChatFooter({
|
|
|
206
225
|
setChannelNotificationsEnabled,
|
|
207
226
|
toggleAuthorProfile,
|
|
208
227
|
authorMessageAction,
|
|
228
|
+
openReactionPicker,
|
|
209
229
|
};
|
|
210
230
|
const authorMessageLabel = composing ? null : authorMessageAction?.label ?? null;
|
|
211
231
|
|
|
@@ -215,6 +235,7 @@ export function useChatFooter({
|
|
|
215
235
|
if (!composing && selectedMessage) {
|
|
216
236
|
if (canSend && failedSend) hints.push({ id: "retry", key: "Enter", label: "retry", title: "Send Again", onPress: () => latest.current.retryMessage(latest.current.selectedIdx) });
|
|
217
237
|
else if (canSend) hints.push({ id: "reply", key: "Enter", label: "reply", title: "Reply", onPress: () => latest.current.beginReplyTo(latest.current.selectedIdx, { deferFocus: true }) });
|
|
238
|
+
if (canReact) hints.push({ id: "react", key: "+", label: " react", title: "Add Reaction", onPress: () => latest.current.openReactionPicker?.(latest.current.selectedIdx) });
|
|
218
239
|
if (canEdit) hints.push({ id: "edit", key: "e", label: "dit", title: "Edit Message", onPress: () => { latest.current.beginEditMessage(latest.current.selectedIdx, { deferFocus: true }); } });
|
|
219
240
|
if (openTargets.length > 0) hints.push({ id: "open", key: "o", label: "pen", title: openTargetTitle, onPress: () => { void latest.current.openSelectedTargets(); } });
|
|
220
241
|
// Every author but a Discord ghost has a card, if only their name and a way to write to them.
|
|
@@ -271,6 +292,7 @@ export function useChatFooter({
|
|
|
271
292
|
failedSend,
|
|
272
293
|
canCycleChannels,
|
|
273
294
|
canEdit,
|
|
295
|
+
canReact,
|
|
274
296
|
canFocusSidebar,
|
|
275
297
|
canSend,
|
|
276
298
|
composing,
|