gloomberb 0.16.1 → 0.16.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/package.json +2 -1
- package/src/api-client/beneficial-owners.ts +92 -0
- package/src/api-client/data.ts +26 -8
- package/src/api-client/errors.ts +12 -0
- package/src/api-client/geo.ts +363 -0
- package/src/api-client/index.ts +2 -0
- package/src/api-client/market-discovery.ts +10 -0
- package/src/api-client/paths.ts +30 -1
- package/src/api-client/perps.ts +37 -0
- package/src/api-client/request.ts +5 -2
- package/src/api-client/types.ts +2 -0
- package/src/brokers/account-cache.ts +24 -0
- package/src/cli/commands/command-utils.ts +8 -0
- package/src/cli/commands/crypto-hints.ts +75 -0
- package/src/cli/commands/market.ts +414 -106
- package/src/cli/commands/overview.ts +77 -32
- package/src/cli/commands/ticker.ts +101 -43
- package/src/cli/desktop-pane-shot.ts +34 -4
- package/src/cli/freshness.ts +61 -0
- package/src/cli/help.ts +1 -0
- package/src/cli/helpers.ts +4 -8
- package/src/cli/index.ts +12 -2
- package/src/cli/listing-arg.ts +321 -0
- package/src/cli/pane-functions/access-gate.ts +42 -0
- package/src/cli/pane-functions/catalog.ts +28 -1
- package/src/cli/pane-functions/data.ts +3 -1
- package/src/cli/pane-functions/dom.ts +20 -2
- package/src/cli/pane-functions/freshness.ts +400 -0
- package/src/cli/pane-functions/function-help.ts +27 -20
- package/src/cli/pane-functions/headless.ts +39 -11
- package/src/cli/pane-functions/index.ts +15 -4
- package/src/cli/pane-functions/options.ts +3 -0
- package/src/cli/pane-functions/report.ts +4 -0
- package/src/cli/pane-functions/resolver.ts +35 -7
- package/src/cli/pane-functions/screenshot-evidence.ts +2 -0
- package/src/cli/pane-functions/screenshot.ts +7 -3
- package/src/cli/result.ts +41 -27
- package/src/cli/ticker-resolution.ts +7 -5
- package/src/components/chart/composite/composite-chart.tsx +88 -2536
- package/src/components/chart/composite/drawing-store.ts +59 -0
- package/src/components/chart/composite/legend.tsx +319 -0
- package/src/components/chart/composite/panel-bitmap.ts +139 -0
- package/src/components/chart/composite/panel-gestures.ts +59 -0
- package/src/components/chart/composite/panel-labels.ts +107 -0
- package/src/components/chart/composite/panel-surface.tsx +876 -0
- package/src/components/chart/composite/tool-catalog.ts +98 -0
- package/src/components/chart/composite/toolbar.tsx +186 -0
- package/src/components/chart/composite/tools.ts +8 -0
- package/src/components/chart/composite/use-composite-chart-keyboard.ts +703 -0
- package/src/components/chart/composite/use-composite-viewport.ts +143 -0
- package/src/components/command-bar/list/model.ts +5 -0
- package/src/components/command-bar/list/view.tsx +16 -3
- package/src/components/command-bar/pane-templates/workflow.ts +1 -0
- package/src/components/command-bar/routes/ticker-search/actions.ts +5 -0
- package/src/components/command-bar/workflow/ops.ts +1 -1
- package/src/components/command-bar/workflow/tickers.ts +6 -0
- package/src/components/data-table/view.tsx +29 -10
- package/src/components/feedback-dialog.tsx +2 -1
- package/src/components/form-modal/field-row.tsx +2 -2
- package/src/components/layout/detached-pane-shell.tsx +6 -3
- package/src/components/layout/pane/content.tsx +23 -10
- package/src/components/layout/pane/error-boundary.tsx +103 -0
- package/src/components/layout/pane/footer/registration.tsx +68 -23
- package/src/components/layout/pane/header.tsx +11 -11
- package/src/components/layout/shell/menu.ts +2 -1
- package/src/components/layout/shell/pane/actions.ts +2 -1
- package/src/components/layout/shell/pane/layers.tsx +14 -3
- package/src/components/metric-treemap/heat-surface.tsx +43 -16
- package/src/components/metric-treemap/heat-tiles.ts +18 -0
- package/src/components/metric-treemap/layout.ts +2 -0
- package/src/components/onboarding/onboarding-keyboard.ts +311 -0
- package/src/components/onboarding/onboarding-wizard.tsx +101 -788
- package/src/components/onboarding/use-onboarding-broker-form.ts +263 -0
- package/src/components/onboarding/use-onboarding-progress.ts +298 -0
- package/src/components/onboarding/use-onboarding-upgrade.ts +83 -0
- package/src/components/ticker/list-table-view.tsx +13 -1
- package/src/components/ui/fields.tsx +8 -0
- package/src/components/ui/range-track.tsx +10 -3
- package/src/components/ui/status.tsx +8 -2
- package/src/components/ui/tabs.tsx +7 -4
- package/src/components/ui/text-prompt-dialog.tsx +4 -2
- package/src/data/config/store/normalize.ts +17 -1
- package/src/i18n/es.ts +19 -1
- package/src/i18n/ja.ts +19 -1
- package/src/i18n/ko.ts +19 -1
- package/src/i18n/zh-cn.ts +19 -1
- package/src/i18n/zh-tw.ts +19 -1
- package/src/market-data/coordinator/chart.ts +1 -1
- package/src/market-data/coordinator/quotes.ts +23 -4
- package/src/market-data/fx-closes.ts +72 -0
- package/src/market-data/market/freshness.ts +78 -6
- package/src/market-data/market/session-close-note.ts +57 -0
- package/src/market-data/market/status.ts +151 -0
- package/src/market-data/published-apac-sessions.ts +66 -0
- package/src/market-data/quotes/contributions.ts +2 -0
- package/src/market-data/quotes/resolution.ts +2 -0
- package/src/market-data/quotes/screener-live-quotes.ts +49 -4
- package/src/plugins/builtin/account-management/pane.tsx +4 -0
- package/src/plugins/builtin/alerts/cli.ts +10 -5
- package/src/plugins/builtin/alerts/index.tsx +1 -0
- package/src/plugins/builtin/analytics/metrics.ts +8 -3
- package/src/plugins/builtin/analytics/risk-client.ts +191 -66
- package/src/plugins/builtin/analytics/risk-fx.ts +102 -0
- package/src/plugins/builtin/analytics/risk-headless.ts +19 -13
- package/src/plugins/builtin/analytics/risk-model.ts +45 -17
- package/src/plugins/builtin/analytics/risk-pane.tsx +1 -0
- package/src/plugins/builtin/analytics/risk-test-data.ts +25 -1
- package/src/plugins/builtin/attention/headless.ts +6 -4
- package/src/plugins/builtin/attention/index.tsx +1 -1
- package/src/plugins/builtin/attention/pane.tsx +1 -1
- package/src/plugins/builtin/awards/headless.ts +1 -0
- package/src/plugins/builtin/awards/pane.tsx +1 -1
- package/src/plugins/builtin/backtest/headless.ts +1 -0
- package/src/plugins/builtin/bond-calculator/headless.ts +1 -0
- package/src/plugins/builtin/buildout/index.tsx +1 -0
- package/src/plugins/builtin/catalysts/headless.ts +3 -1
- package/src/plugins/builtin/cds/headless.ts +2 -0
- package/src/plugins/builtin/central-bank-rates/headless.ts +1 -0
- package/src/plugins/builtin/chart-composer/headless.ts +38 -3
- package/src/plugins/builtin/chart-composer/index.tsx +3 -1
- package/src/plugins/builtin/chart-composer/series-expression.ts +18 -2
- package/src/plugins/builtin/chat/channels.ts +19 -3
- package/src/plugins/builtin/chat/content/composer-runtime.ts +28 -13
- package/src/plugins/builtin/chat/content/footer.tsx +15 -6
- package/src/plugins/builtin/chat/content/index.tsx +120 -21
- package/src/plugins/builtin/chat/content/new-dm-dialog.tsx +261 -113
- package/src/plugins/builtin/chat/content/transcript.tsx +20 -2
- package/src/plugins/builtin/chat/direct-messages.ts +200 -0
- package/src/plugins/builtin/chat/index.tsx +1 -0
- package/src/plugins/builtin/chat/message/desktop.tsx +3 -0
- package/src/plugins/builtin/chat/message/header.tsx +16 -6
- package/src/plugins/builtin/chat/message/inline-tokens.tsx +72 -32
- package/src/plugins/builtin/chat/message/profile-popover.tsx +96 -12
- package/src/plugins/builtin/chat/message/terminal.tsx +3 -0
- package/src/plugins/builtin/chat/message/types.ts +14 -2
- package/src/plugins/builtin/chat/profile-popover.ts +18 -13
- package/src/plugins/builtin/clinical-trials/index.tsx +1 -0
- package/src/plugins/builtin/cloud/askg/executor.ts +2 -1
- package/src/plugins/builtin/cloud/plugin.tsx +1 -0
- package/src/plugins/builtin/cloud/team/module.tsx +1 -0
- package/src/plugins/builtin/cloud/thesis/module.tsx +1 -0
- package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
- package/src/plugins/builtin/comment-letters/index.tsx +1 -0
- package/src/plugins/builtin/company-attention/headless.ts +5 -1
- package/src/plugins/builtin/company-attention/pane.tsx +1 -1
- package/src/plugins/builtin/company-kpis/headless.ts +1 -0
- package/src/plugins/builtin/congress-trades/headless.ts +1 -0
- package/src/plugins/builtin/correlation/compute.ts +59 -16
- package/src/plugins/builtin/correlation/geo.ts +34 -0
- package/src/plugins/builtin/correlation/headless-schema.ts +4 -1
- package/src/plugins/builtin/correlation/headless.ts +42 -8
- package/src/plugins/builtin/correlation/history.ts +2 -0
- package/src/plugins/builtin/correlation/index.tsx +68 -14
- package/src/plugins/builtin/correlation/matrix/model.ts +17 -2
- package/src/plugins/builtin/correlation/matrix/selection.ts +5 -3
- package/src/plugins/builtin/correlation/relationship/model.ts +1 -1
- package/src/plugins/builtin/correlation/relationship/pane.tsx +4 -2
- package/src/plugins/builtin/correlation/relationship/view-model.ts +16 -1
- package/src/plugins/builtin/correlation/settings.ts +1 -1
- package/src/plugins/builtin/cot/headless.ts +6 -3
- package/src/plugins/builtin/cot/index.tsx +3 -3
- package/src/plugins/builtin/cot/model.ts +36 -3
- package/src/plugins/builtin/cpi/headless.ts +4 -0
- package/src/plugins/builtin/credit-boards/headless.ts +2 -0
- package/src/plugins/builtin/credit-conditions/headless.ts +1 -0
- package/src/plugins/builtin/credit-documents/gauge.tsx +5 -8
- package/src/plugins/builtin/credit-documents/headless.ts +2 -0
- package/src/plugins/builtin/crypto-board/headless.ts +3 -0
- package/src/plugins/builtin/custom-view/loader.ts +1 -1
- package/src/plugins/builtin/debt-maturities/headless.ts +4 -0
- package/src/plugins/builtin/dividend-yield/headless.ts +1 -0
- package/src/plugins/builtin/doe/headless.ts +7 -0
- package/src/plugins/builtin/doe/range-bar.tsx +7 -37
- package/src/plugins/builtin/earnings/headless.ts +5 -0
- package/src/plugins/builtin/earnings-calls/headless.ts +1 -0
- package/src/plugins/builtin/earnings-ripple/client.ts +91 -18
- package/src/plugins/builtin/earnings-ripple/headless.ts +28 -8
- package/src/plugins/builtin/earnings-ripple/index.tsx +2 -2
- package/src/plugins/builtin/earnings-ripple/model.ts +97 -7
- package/src/plugins/builtin/earnings-ripple/pane.tsx +148 -23
- package/src/plugins/builtin/econ/index.tsx +1 -0
- package/src/plugins/builtin/econ-statistics/headless.ts +2 -0
- package/src/plugins/builtin/equity-screener/headless.ts +2 -0
- package/src/plugins/builtin/estimate-revisions/headless.ts +1 -0
- package/src/plugins/builtin/executives/index.tsx +1 -0
- package/src/plugins/builtin/exposure/headless.ts +3 -1
- package/src/plugins/builtin/fear-greed/headless.ts +2 -0
- package/src/plugins/builtin/filing-events/index.tsx +1 -0
- package/src/plugins/builtin/futures-curve/client.ts +12 -3
- package/src/plugins/builtin/futures-curve/headless.ts +39 -10
- package/src/plugins/builtin/futures-curve/index.tsx +3 -3
- package/src/plugins/builtin/futures-curve/model.ts +188 -4
- package/src/plugins/builtin/futures-curve/pane.tsx +51 -9
- package/src/plugins/builtin/gpu/headless.ts +7 -3
- package/src/plugins/builtin/gpu/ladder.tsx +26 -30
- package/src/plugins/builtin/gpu/model.ts +27 -1
- package/src/plugins/builtin/holders/beneficial-client.ts +209 -0
- package/src/plugins/builtin/holders/beneficial-model.ts +279 -0
- package/src/plugins/builtin/holders/beneficial-report.ts +126 -0
- package/src/plugins/builtin/holders/beneficial-view.tsx +241 -0
- package/src/plugins/builtin/holders/headless.ts +139 -5
- package/src/plugins/builtin/holders/index.tsx +10 -3
- package/src/plugins/builtin/holders/pane.tsx +20 -3
- package/src/plugins/builtin/holders/report-header.ts +95 -0
- package/src/plugins/builtin/holders/table-model.ts +20 -5
- package/src/plugins/builtin/holders/thirteenf-match.ts +29 -1
- package/src/plugins/builtin/holders/types.ts +2 -1
- package/src/plugins/builtin/insider/headless.ts +2 -0
- package/src/plugins/builtin/ipo-calendar/headless.ts +1 -0
- package/src/plugins/builtin/iv-history/headless.ts +4 -1
- package/src/plugins/builtin/jobs/headless.ts +1 -0
- package/src/plugins/builtin/kelly-sizer/index.tsx +1 -0
- package/src/plugins/builtin/macro-day/headless.ts +2 -0
- package/src/plugins/builtin/market-halts/index.tsx +1 -0
- package/src/plugins/builtin/market-heatmap/data.ts +2 -0
- package/src/plugins/builtin/market-heatmap/headless.ts +135 -0
- package/src/plugins/builtin/market-heatmap/index.tsx +39 -46
- package/src/plugins/builtin/market-heatmap/model.ts +146 -0
- package/src/plugins/builtin/market-heatmap/portfolio.ts +23 -4
- package/src/plugins/builtin/market-movers/headless.ts +2 -0
- package/src/plugins/builtin/market-valuation/headless.ts +2 -0
- package/src/plugins/builtin/members/client.ts +20 -3
- package/src/plugins/builtin/members/headless.ts +5 -3
- package/src/plugins/builtin/members/model.ts +10 -2
- package/src/plugins/builtin/members/pane.tsx +13 -6
- package/src/plugins/builtin/mna/distress/headless.ts +1 -0
- package/src/plugins/builtin/mna/headless.ts +1 -0
- package/src/plugins/builtin/money-markets/headless.ts +1 -0
- package/src/plugins/builtin/news/headless.ts +2 -0
- package/src/plugins/builtin/news/wire/index.tsx +8 -1
- package/src/plugins/builtin/notes/cli.ts +14 -6
- package/src/plugins/builtin/notes/index.tsx +1 -0
- package/src/plugins/builtin/openfda/index.tsx +1 -0
- package/src/plugins/builtin/options-calculator/headless.ts +2 -0
- package/src/plugins/builtin/options-positioning/headless.ts +3 -0
- package/src/plugins/builtin/options-scenario/headless.ts +5 -0
- package/src/plugins/builtin/pe-band/client.ts +48 -3
- package/src/plugins/builtin/pe-band/headless.ts +25 -7
- package/src/plugins/builtin/pe-band/model.ts +92 -16
- package/src/plugins/builtin/pe-band/pane.tsx +33 -16
- package/src/plugins/builtin/perps/client.ts +50 -3
- package/src/plugins/builtin/perps/headless.ts +144 -16
- package/src/plugins/builtin/perps/index.tsx +6 -6
- package/src/plugins/builtin/perps/model.ts +189 -12
- package/src/plugins/builtin/perps/pane.tsx +248 -47
- package/src/plugins/builtin/portfolio-list/allocation.ts +245 -0
- package/src/plugins/builtin/portfolio-list/cached-account.ts +33 -0
- package/src/plugins/builtin/portfolio-list/cell-version.ts +19 -1
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +328 -29
- package/src/plugins/builtin/portfolio-list/cli/render.ts +230 -39
- package/src/plugins/builtin/portfolio-list/cli/shared.ts +67 -2
- package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +35 -31
- package/src/plugins/builtin/portfolio-list/column-values.ts +124 -47
- package/src/plugins/builtin/portfolio-list/headless.ts +98 -16
- package/src/plugins/builtin/portfolio-list/index.tsx +14 -3
- package/src/plugins/builtin/portfolio-list/live-valuation.ts +7 -5
- package/src/plugins/builtin/portfolio-list/mutations.ts +55 -1
- package/src/plugins/builtin/portfolio-list/pane/data.ts +6 -0
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +47 -13
- package/src/plugins/builtin/portfolio-list/settings.ts +33 -2
- package/src/plugins/builtin/portfolio-list/summary/index.tsx +24 -1
- package/src/plugins/builtin/portfolio-list/summary/totals.ts +26 -7
- package/src/plugins/builtin/power/headless.ts +3 -1
- package/src/plugins/builtin/rate-path/headless.ts +2 -0
- package/src/plugins/builtin/realized-vol/headless.ts +2 -0
- package/src/plugins/builtin/relative-rotation/headless.ts +2 -0
- package/src/plugins/builtin/research/analyst-headless.ts +3 -0
- package/src/plugins/builtin/research/events-headless.ts +2 -0
- package/src/plugins/builtin/research/headless.ts +2 -0
- package/src/plugins/builtin/research/index.tsx +1 -0
- package/src/plugins/builtin/research/relative-valuation-headless.ts +10 -5
- package/src/plugins/builtin/research/relative-valuation-model.ts +11 -3
- package/src/plugins/builtin/research/relative-valuation-pane.tsx +3 -3
- package/src/plugins/builtin/research-search/index.tsx +1 -0
- package/src/plugins/builtin/revenue-breakdown/headless.ts +2 -0
- package/src/plugins/builtin/reverse-dcf/headless.ts +2 -0
- package/src/plugins/builtin/risk-factors/headless.ts +2 -0
- package/src/plugins/builtin/scanner/flow-history.ts +2 -13
- package/src/plugins/builtin/scanner/headless.ts +14 -0
- package/src/plugins/builtin/seasonality/headless.ts +2 -0
- package/src/plugins/builtin/sec/command-bar-search.ts +14 -4
- package/src/plugins/builtin/sec/filing-content.ts +42 -17
- package/src/plugins/builtin/sec/forms.ts +12 -0
- package/src/plugins/builtin/sec/headless.ts +2 -0
- package/src/plugins/builtin/sectors/client.ts +1 -0
- package/src/plugins/builtin/sectors/headless.ts +9 -1
- package/src/plugins/builtin/sectors/sector-model.ts +2 -0
- package/src/plugins/builtin/shared/crypto-pair.ts +14 -0
- package/src/plugins/builtin/shared/locked-rows.tsx +1 -1
- package/src/plugins/builtin/shared/report-freshness.ts +57 -0
- package/src/plugins/builtin/shared/research-cells.tsx +4 -9
- package/src/plugins/builtin/short-interest/headless.ts +2 -0
- package/src/plugins/builtin/short-interest/watch-headless.ts +1 -0
- package/src/plugins/builtin/short-volume/headless.ts +1 -0
- package/src/plugins/builtin/social-mentions/headless.ts +1 -0
- package/src/plugins/builtin/supply-chain/headless.ts +7 -1
- package/src/plugins/builtin/supply-chain/index.tsx +10 -1
- package/src/plugins/builtin/supply-chain/model.ts +27 -2
- package/src/plugins/builtin/supply-chain/pane.tsx +71 -32
- package/src/plugins/builtin/themes/headless.ts +3 -0
- package/src/plugins/builtin/thirteenf/headless.ts +110 -25
- package/src/plugins/builtin/thirteenf/report-notes.ts +149 -0
- package/src/plugins/builtin/ticker-detail/headless.ts +7 -1
- package/src/plugins/builtin/ticker-detail/index.tsx +1 -0
- package/src/plugins/builtin/ticker-detail/overview/model.ts +9 -2
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +26 -26
- package/src/plugins/builtin/time-sales/headless.ts +5 -1
- package/src/plugins/builtin/treasury-auctions/headless.ts +1 -0
- package/src/plugins/builtin/volatility/headless.ts +6 -1
- package/src/plugins/builtin/world-indices/headless.ts +2 -0
- package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +157 -0
- package/src/plugins/builtin/world-venue-map/basemap.ts +214 -0
- package/src/plugins/builtin/world-venue-map/client.ts +45 -0
- package/src/plugins/builtin/world-venue-map/entity-detail.tsx +147 -0
- package/src/plugins/builtin/world-venue-map/entity-table.ts +59 -0
- package/src/plugins/builtin/world-venue-map/evidence.ts +77 -0
- package/src/plugins/builtin/world-venue-map/feed.ts +293 -0
- package/src/plugins/builtin/world-venue-map/geo-draw.tsx +248 -0
- package/src/plugins/builtin/world-venue-map/geo-series.ts +142 -0
- package/src/plugins/builtin/world-venue-map/geo-svg.tsx +447 -0
- package/src/plugins/builtin/world-venue-map/headless.ts +146 -0
- package/src/plugins/builtin/world-venue-map/ids.ts +1 -0
- package/src/plugins/builtin/world-venue-map/index.ts +67 -4
- package/src/plugins/builtin/world-venue-map/layered-pane.tsx +552 -0
- package/src/plugins/builtin/world-venue-map/layers.ts +348 -0
- package/src/plugins/builtin/world-venue-map/map-symbols.ts +220 -0
- package/src/plugins/builtin/world-venue-map/map.tsx +381 -45
- package/src/plugins/builtin/world-venue-map/model.ts +7 -4
- package/src/plugins/builtin/world-venue-map/natural-earth/index.chunk.ts +199 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/world-50m.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/pane.tsx +28 -43
- package/src/plugins/builtin/world-venue-map/use-geo.ts +55 -0
- package/src/plugins/builtin/world-venue-map/venue-header.tsx +32 -0
- package/src/plugins/builtin/yield-curve/headless.ts +16 -0
- package/src/plugins/loader.ts +13 -1
- package/src/plugins/registry/pane-settings.ts +1 -0
- package/src/renderers/dom/build-assets.ts +81 -3
- package/src/renderers/dom/data-table/row.tsx +2 -0
- package/src/renderers/dom/desktop/controls.tsx +7 -3
- package/src/renderers/dom/desktop/list-view.tsx +35 -10
- package/src/renderers/dom/desktop/popover.tsx +73 -14
- package/src/renderers/dom/host/input.tsx +14 -3
- package/src/renderers/dom/styles.css +6 -7
- package/src/renderers/electrobun/view/backend-rpc.ts +10 -4
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -0
- package/src/renderers/electrobun/view/rpc-timeout.ts +14 -3
- package/src/renderers/opentui/host.tsx +5 -0
- package/src/sources/gloomberb-cloud/index.ts +25 -4
- package/src/sources/gloomberb-cloud/normalizers.ts +27 -3
- package/src/sources/provider-router/cached-routes.ts +4 -1
- package/src/sources/provider-router/financials.ts +8 -7
- package/src/sources/provider-router/history.ts +15 -10
- package/src/sources/sec-registrant.ts +75 -0
- package/src/state/app/context/index.tsx +24 -8
- package/src/state/hooks/quote-streaming.ts +41 -26
- package/src/sync/core-contributors.ts +4 -0
- package/src/telemetry/crash-reports.ts +4 -1
- package/src/test-support/cli-context.ts +10 -2
- package/src/theme/heat-colors.ts +266 -84
- package/src/time-series/resolve.ts +1 -1
- package/src/time-series/use-chart-resolution.ts +1 -1
- package/src/types/context-menu.ts +6 -0
- package/src/types/data-provider.ts +2 -0
- package/src/types/financials.ts +3 -0
- package/src/types/headless.ts +79 -2
- package/src/types/plugin.ts +20 -1
- package/src/types/ticker.ts +15 -0
- package/src/ui/host.tsx +14 -0
- package/src/updater/index.ts +9 -11
- package/src/utils/async-deadline.ts +21 -0
- package/src/utils/cli-output.ts +5 -1
- package/src/utils/crypto-pair.ts +41 -0
- package/src/utils/currency-units.ts +14 -0
- package/src/utils/depositary-receipt.ts +26 -0
- package/src/utils/exchanges.ts +72 -0
- package/src/utils/fire-and-forget.ts +24 -0
- package/src/utils/format.ts +13 -0
- package/src/utils/price-earnings.ts +70 -3
- package/src/utils/price-history.ts +58 -13
- package/src/utils/rpc-timeout-error.ts +27 -0
- package/src/utils/sec.ts +13 -1
- package/src/utils/utc-time.ts +79 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
2
|
+
import type { ResolvedSeries } from "../../../time-series/types";
|
|
3
|
+
import {
|
|
4
|
+
buildCompositeNavigationFrame,
|
|
5
|
+
compositeNavigationDataViewport,
|
|
6
|
+
compositeViewportPositions,
|
|
7
|
+
fitCompositeViewport,
|
|
8
|
+
panCompositeViewport,
|
|
9
|
+
sameCompositeViewport,
|
|
10
|
+
shouldResetCompositeViewport,
|
|
11
|
+
zoomCompositeViewport,
|
|
12
|
+
type CompositeNavigationFrame,
|
|
13
|
+
type CompositeViewportRange,
|
|
14
|
+
} from "./interactions";
|
|
15
|
+
import type { CompositeChartProps } from "./types";
|
|
16
|
+
|
|
17
|
+
/** How far past the first loaded observation a backfilling chart may pan, as a fraction of the view. */
|
|
18
|
+
const HISTORICAL_PADDING_RATIO = 0.5;
|
|
19
|
+
|
|
20
|
+
export function useCompositeViewport({
|
|
21
|
+
viewport,
|
|
22
|
+
viewportResetKey,
|
|
23
|
+
visibleSeries,
|
|
24
|
+
marketTimelineSeries,
|
|
25
|
+
allowHistoricalBackfill,
|
|
26
|
+
onViewportChange,
|
|
27
|
+
}: {
|
|
28
|
+
viewport: CompositeChartProps["viewport"];
|
|
29
|
+
viewportResetKey: CompositeChartProps["viewportResetKey"];
|
|
30
|
+
visibleSeries: ResolvedSeries[];
|
|
31
|
+
marketTimelineSeries: ResolvedSeries[];
|
|
32
|
+
allowHistoricalBackfill: boolean;
|
|
33
|
+
onViewportChange: CompositeChartProps["onViewportChange"];
|
|
34
|
+
}) {
|
|
35
|
+
const previousAuthoredViewportRef = useRef<CompositeViewportRange | null>(viewport ?? null);
|
|
36
|
+
const previousViewportResetKeyRef = useRef(viewportResetKey);
|
|
37
|
+
// The user owns this once they navigate. Data refreshes never rewrite it;
|
|
38
|
+
// only the authored viewport changing or an explicit reset clears it.
|
|
39
|
+
const [userViewport, setUserViewport] = useState<CompositeViewportRange | null>(null);
|
|
40
|
+
const hasViewportResetKey = viewportResetKey !== undefined
|
|
41
|
+
|| previousViewportResetKeyRef.current !== undefined;
|
|
42
|
+
const authoredViewportChanged = hasViewportResetKey
|
|
43
|
+
? previousViewportResetKeyRef.current !== viewportResetKey
|
|
44
|
+
: shouldResetCompositeViewport(
|
|
45
|
+
previousAuthoredViewportRef.current,
|
|
46
|
+
viewport ?? null,
|
|
47
|
+
);
|
|
48
|
+
const navigationFrame = useMemo(
|
|
49
|
+
() => buildCompositeNavigationFrame(visibleSeries, marketTimelineSeries, {
|
|
50
|
+
historicalPaddingRatio: allowHistoricalBackfill ? HISTORICAL_PADDING_RATIO : 0,
|
|
51
|
+
}),
|
|
52
|
+
[allowHistoricalBackfill, marketTimelineSeries, visibleSeries],
|
|
53
|
+
);
|
|
54
|
+
const authoredViewport = useMemo(() => {
|
|
55
|
+
// The requested dates own the axis, including gaps in a cached or partial
|
|
56
|
+
// response. Fitting them to available observations silently changes the
|
|
57
|
+
// research period. User pan/zoom gestures retain their navigation limits.
|
|
58
|
+
if (viewport && Number.isFinite(viewport.start.getTime())
|
|
59
|
+
&& Number.isFinite(viewport.end.getTime()) && viewport.start <= viewport.end) return viewport;
|
|
60
|
+
return navigationFrame ? compositeNavigationDataViewport(navigationFrame) : null;
|
|
61
|
+
}, [navigationFrame, viewport]);
|
|
62
|
+
const activeUserViewport = authoredViewportChanged ? null : userViewport;
|
|
63
|
+
const effectiveViewport = activeUserViewport ?? authoredViewport;
|
|
64
|
+
const userViewportStart = activeUserViewport?.start.getTime() ?? null;
|
|
65
|
+
const userViewportEnd = activeUserViewport?.end.getTime() ?? null;
|
|
66
|
+
const lastReportedViewportRef = useRef<string | null>(null);
|
|
67
|
+
const viewportInteractionRef = useRef<"pan" | "reset" | "zoom">("reset");
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
if (!onViewportChange) return;
|
|
70
|
+
const key = userViewportStart === null || userViewportEnd === null
|
|
71
|
+
? "none"
|
|
72
|
+
: `${userViewportStart}:${userViewportEnd}`;
|
|
73
|
+
// The callback drives adaptive data loading. Seed it from the authored
|
|
74
|
+
// viewport without echoing that controlled value back into the loader.
|
|
75
|
+
if (lastReportedViewportRef.current === null) {
|
|
76
|
+
lastReportedViewportRef.current = key;
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (lastReportedViewportRef.current === key) return;
|
|
80
|
+
lastReportedViewportRef.current = key;
|
|
81
|
+
onViewportChange(
|
|
82
|
+
userViewportStart === null || userViewportEnd === null
|
|
83
|
+
? null
|
|
84
|
+
: { start: new Date(userViewportStart), end: new Date(userViewportEnd) },
|
|
85
|
+
viewportInteractionRef.current,
|
|
86
|
+
);
|
|
87
|
+
}, [onViewportChange, userViewportEnd, userViewportStart]);
|
|
88
|
+
|
|
89
|
+
useEffect(() => {
|
|
90
|
+
previousAuthoredViewportRef.current = viewport ?? null;
|
|
91
|
+
previousViewportResetKeyRef.current = viewportResetKey;
|
|
92
|
+
if (authoredViewportChanged && userViewport) {
|
|
93
|
+
viewportInteractionRef.current = "reset";
|
|
94
|
+
setUserViewport(null);
|
|
95
|
+
}
|
|
96
|
+
}, [authoredViewportChanged, userViewport, viewport, viewportResetKey]);
|
|
97
|
+
|
|
98
|
+
const navigate = useCallback((
|
|
99
|
+
kind: "pan" | "zoom",
|
|
100
|
+
compute: (base: CompositeViewportRange, frame: CompositeNavigationFrame) => CompositeViewportRange,
|
|
101
|
+
gesture?: { frame: CompositeNavigationFrame; from: CompositeViewportRange },
|
|
102
|
+
) => {
|
|
103
|
+
const frame = gesture?.frame ?? navigationFrame;
|
|
104
|
+
if (!frame) return;
|
|
105
|
+
viewportInteractionRef.current = kind;
|
|
106
|
+
setUserViewport((current) => {
|
|
107
|
+
const base = gesture?.from ?? current ?? authoredViewport;
|
|
108
|
+
if (!base) return current;
|
|
109
|
+
const next = compute(base, frame);
|
|
110
|
+
// Once navigated, the window is the user's until they reset it, even if
|
|
111
|
+
// a gesture happens to land back on the authored range: the owner may
|
|
112
|
+
// echo a navigated range back as the authored one, and dropping to null
|
|
113
|
+
// there would reload the original range under the pointer.
|
|
114
|
+
return sameCompositeViewport(next, current ?? base) ? current : next;
|
|
115
|
+
});
|
|
116
|
+
}, [authoredViewport, navigationFrame]);
|
|
117
|
+
const panViewport = useCallback((
|
|
118
|
+
deltaPositions: number,
|
|
119
|
+
gesture?: { frame: CompositeNavigationFrame; from: CompositeViewportRange },
|
|
120
|
+
) => {
|
|
121
|
+
navigate("pan", (base, frame) => panCompositeViewport(frame, base, deltaPositions), gesture);
|
|
122
|
+
}, [navigate]);
|
|
123
|
+
const panViewportByRatio = useCallback((shiftRatio: number) => {
|
|
124
|
+
if (!navigationFrame || !effectiveViewport) return;
|
|
125
|
+
const positions = compositeViewportPositions(navigationFrame, effectiveViewport);
|
|
126
|
+
if (!positions) return;
|
|
127
|
+
panViewport(shiftRatio * Math.max(positions.end - positions.start, Number.EPSILON));
|
|
128
|
+
}, [effectiveViewport, navigationFrame, panViewport]);
|
|
129
|
+
const zoomViewport = useCallback((zoomFactor: number, anchorRatio = 1) => {
|
|
130
|
+
navigate("zoom", (base, frame) => zoomCompositeViewport(frame, base, zoomFactor, anchorRatio));
|
|
131
|
+
}, [navigate]);
|
|
132
|
+
const setViewportRange = useCallback((range: CompositeViewportRange) => {
|
|
133
|
+
navigate("zoom", (_base, frame) => fitCompositeViewport(frame, range));
|
|
134
|
+
}, [navigate]);
|
|
135
|
+
const resetViewport = useCallback(() => {
|
|
136
|
+
viewportInteractionRef.current = "reset";
|
|
137
|
+
setUserViewport(null);
|
|
138
|
+
}, []);
|
|
139
|
+
return {
|
|
140
|
+
navigationFrame, activeUserViewport, effectiveViewport,
|
|
141
|
+
panViewport, panViewportByRatio, zoomViewport, setViewportRange, resetViewport,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
@@ -24,6 +24,11 @@ export interface ResultItem {
|
|
|
24
24
|
lines?: CommandBarResultLine[];
|
|
25
25
|
/** Short tag drawn left of the label: a shortcut, an asset class, a document type. */
|
|
26
26
|
badge?: string;
|
|
27
|
+
/**
|
|
28
|
+
* An instrument's name, drawn muted after the symbol. Listings that share a
|
|
29
|
+
* symbol (SAP on NYSE and XETRA, Saputo as SAP on TSX) differ only here.
|
|
30
|
+
*/
|
|
31
|
+
name?: string;
|
|
27
32
|
right?: string;
|
|
28
33
|
/** Provider type retained for symbol/alias identity checks. */
|
|
29
34
|
instrumentType?: string;
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
TextAttributes,
|
|
12
12
|
type ScrollBoxRenderable,
|
|
13
13
|
} from "../../../ui";
|
|
14
|
-
import { truncateTextSegments, truncateToDisplayWidth } from "../../../utils/format";
|
|
14
|
+
import { displayWidth, truncateTextSegments, truncateToDisplayWidth } from "../../../utils/format";
|
|
15
15
|
import { Spinner } from "../../ui";
|
|
16
16
|
import { useCommandBarPalette } from "../panel/palette";
|
|
17
17
|
import { getRowPresentation } from "../view-model";
|
|
@@ -37,6 +37,9 @@ export type CommandBarListScrollEvent = {
|
|
|
37
37
|
|
|
38
38
|
/** Columns every row gives up to the badge column, badge or not. */
|
|
39
39
|
const BADGE_INDENT = BADGE_COLUMN_WIDTH + BADGE_GAP;
|
|
40
|
+
const NAME_GAP = 2;
|
|
41
|
+
/** Below this a name is a few letters and an ellipsis, which tells nobody apart. */
|
|
42
|
+
const MIN_NAME_WIDTH = 6;
|
|
40
43
|
|
|
41
44
|
interface CommandBarListItemRowProps {
|
|
42
45
|
item: ResultItem;
|
|
@@ -79,7 +82,12 @@ const CommandBarListItemRow = memo(function CommandBarListItemRow({
|
|
|
79
82
|
const labelColumnWidth = Math.max(1, labelWidth - BADGE_INDENT);
|
|
80
83
|
// A long title stops one cell short of the right column, so its ellipsis
|
|
81
84
|
// never runs into the date or shortcut sitting there.
|
|
82
|
-
const
|
|
85
|
+
const labelSpace = Math.max(1, labelColumnWidth - (trailingWidth > 0 ? 1 : 0));
|
|
86
|
+
const label = truncateToDisplayWidth(presentation.label, labelSpace);
|
|
87
|
+
// The name gives way before the symbol: it shrinks to its ellipsis and drops
|
|
88
|
+
// out once fewer than a few characters of it would show.
|
|
89
|
+
const nameSpace = labelSpace - displayWidth(label) - NAME_GAP;
|
|
90
|
+
const name = item.name && nameSpace >= MIN_NAME_WIDTH ? truncateToDisplayWidth(item.name, nameSpace) : "";
|
|
83
91
|
// "current" outranks the shortcut on the right; otherwise a badge lifted from
|
|
84
92
|
// `right` must not be repeated there.
|
|
85
93
|
const trailing = badgeConsumesRight(item) && !item.current
|
|
@@ -152,10 +160,15 @@ const CommandBarListItemRow = memo(function CommandBarListItemRow({
|
|
|
152
160
|
<Box width={BADGE_INDENT} flexDirection="row">
|
|
153
161
|
{badge && <CommandBarRowBadge text={badge.text} tone={badge.tone} width={BADGE_COLUMN_WIDTH} />}
|
|
154
162
|
</Box>
|
|
155
|
-
<Box width={labelColumnWidth}>
|
|
163
|
+
<Box width={labelColumnWidth} flexDirection="row">
|
|
156
164
|
<Text fg={isSelected ? palette.selectedText : presentation.primaryMuted ? palette.subtle : palette.text}>
|
|
157
165
|
{label}
|
|
158
166
|
</Text>
|
|
167
|
+
{name && (
|
|
168
|
+
<Text fg={isSelected ? palette.selectedText : palette.subtle}>
|
|
169
|
+
{" ".repeat(NAME_GAP) + name}
|
|
170
|
+
</Text>
|
|
171
|
+
)}
|
|
159
172
|
</Box>
|
|
160
173
|
<Box width={trailingWidth}>
|
|
161
174
|
<Text
|
|
@@ -64,6 +64,9 @@ export function useCommandBarTickerSearchActions({
|
|
|
64
64
|
// text goes quiet rather than repeating it.
|
|
65
65
|
const badge = formatInstrumentBadge(candidate);
|
|
66
66
|
const right = candidate.exchangeLabel || candidate.primaryExchangeLabel || candidate.right || undefined;
|
|
67
|
+
// The candidate's detail leads with the name; the rest repeats the badge or venue.
|
|
68
|
+
const leadingName = candidate.detail.split(" | ")[0]?.trim();
|
|
69
|
+
const name = leadingName && leadingName.toUpperCase() !== candidate.label.toUpperCase() ? leadingName : undefined;
|
|
67
70
|
|
|
68
71
|
if (candidate.kind === "ticker" && candidate.ticker) {
|
|
69
72
|
return {
|
|
@@ -74,6 +77,7 @@ export function useCommandBarTickerSearchActions({
|
|
|
74
77
|
instrumentType: candidate.instrumentType,
|
|
75
78
|
detail,
|
|
76
79
|
badge,
|
|
80
|
+
name,
|
|
77
81
|
right,
|
|
78
82
|
category: candidate.category,
|
|
79
83
|
kind: "ticker",
|
|
@@ -97,6 +101,7 @@ export function useCommandBarTickerSearchActions({
|
|
|
97
101
|
instrumentType: candidate.instrumentType,
|
|
98
102
|
detail,
|
|
99
103
|
badge,
|
|
104
|
+
name,
|
|
100
105
|
right,
|
|
101
106
|
category: candidate.category,
|
|
102
107
|
kind: "search",
|
|
@@ -252,7 +252,7 @@ async function resolvePaneTemplateOptions(
|
|
|
252
252
|
const rawInput = resolvedOptions?.arg ?? resolvedOptions?.values?.tickers ?? "";
|
|
253
253
|
const symbols = !String(rawInput).trim() && template.shortcut?.openWithoutArg
|
|
254
254
|
? []
|
|
255
|
-
: await resolveTickerListInput(rawInput, baseContext.activeCollectionId, deps);
|
|
255
|
+
: await resolveTickerListInput(rawInput, baseContext.activeCollectionId, deps, template.shortcut?.keepArgToken);
|
|
256
256
|
resolvedOptions = {
|
|
257
257
|
...resolvedOptions,
|
|
258
258
|
arg: rawInput,
|
|
@@ -233,12 +233,18 @@ export async function resolveTickerListInput(
|
|
|
233
233
|
rawInput: string,
|
|
234
234
|
collectionId: string | null,
|
|
235
235
|
deps: SharedWorkflowDeps,
|
|
236
|
+
keepToken?: (token: string) => boolean,
|
|
236
237
|
): Promise<string[]> {
|
|
237
238
|
const tokens = parseTickerListInput(rawInput);
|
|
238
239
|
const symbols: string[] = [];
|
|
239
240
|
const seen = new Set<string>();
|
|
240
241
|
|
|
241
242
|
for (const token of tokens) {
|
|
243
|
+
if (keepToken?.(token)) {
|
|
244
|
+
if (!seen.has(token)) symbols.push(token);
|
|
245
|
+
seen.add(token);
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
242
248
|
const resolvedTicker = await resolveTickerInputOrThrow(token, null, collectionId, deps, { preserveListingKey: true });
|
|
243
249
|
const symbol = resolvedTicker.symbol;
|
|
244
250
|
|
|
@@ -593,26 +593,45 @@ export function DataTableView<
|
|
|
593
593
|
&& (!isNavigable || isNavigable(item, index))
|
|
594
594
|
), [effectiveSelectedIndex, isNavigable]);
|
|
595
595
|
|
|
596
|
+
// The row handlers reach the latest cursor logic through a ref, so their
|
|
597
|
+
// identity survives a parent render. Most callers build `selection` inline,
|
|
598
|
+
// which used to give every handler a new identity on each render and made
|
|
599
|
+
// every visible row re-render its cells, even when nothing in it changed.
|
|
600
|
+
const rowHandlerStateRef = useRef({
|
|
601
|
+
activateIndex,
|
|
602
|
+
onRowContextMenu: tableProps.onRowContextMenu,
|
|
603
|
+
onRowMouseDown: tableProps.onRowMouseDown,
|
|
604
|
+
updateCursorIndex,
|
|
605
|
+
});
|
|
606
|
+
rowHandlerStateRef.current = {
|
|
607
|
+
activateIndex,
|
|
608
|
+
onRowContextMenu: tableProps.onRowContextMenu,
|
|
609
|
+
onRowMouseDown: tableProps.onRowMouseDown,
|
|
610
|
+
updateCursorIndex,
|
|
611
|
+
};
|
|
612
|
+
|
|
596
613
|
const handleTableSelect = useCallback((_item: T, index: number) => {
|
|
597
|
-
updateCursorIndex(index, { commit: "immediate" });
|
|
598
|
-
}, [
|
|
614
|
+
rowHandlerStateRef.current.updateCursorIndex(index, { commit: "immediate" });
|
|
615
|
+
}, []);
|
|
599
616
|
|
|
600
617
|
const handleTableActivate = useCallback((_item: T, index: number) => {
|
|
601
|
-
activateIndex(index);
|
|
602
|
-
}, [
|
|
618
|
+
rowHandlerStateRef.current.activateIndex(index);
|
|
619
|
+
}, []);
|
|
603
620
|
|
|
604
621
|
const handleRowMouseDown = useCallback((item: T, index: number, event: any) => {
|
|
605
|
-
const
|
|
622
|
+
const latest = rowHandlerStateRef.current;
|
|
623
|
+
const handled = latest.onRowMouseDown?.(item, index, event);
|
|
606
624
|
if (handled === true) {
|
|
607
|
-
updateCursorIndex(index, { commit: "immediate" });
|
|
625
|
+
latest.updateCursorIndex(index, { commit: "immediate" });
|
|
608
626
|
}
|
|
609
627
|
return handled;
|
|
610
|
-
}, [
|
|
628
|
+
}, []);
|
|
611
629
|
|
|
612
630
|
const handleRowContextMenu = useCallback((item: T, index: number, event: any) => {
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
631
|
+
const latest = rowHandlerStateRef.current;
|
|
632
|
+
latest.updateCursorIndex(index, { commit: "immediate" });
|
|
633
|
+
latest.onRowContextMenu?.(item, index, event);
|
|
634
|
+
}, []);
|
|
616
635
|
|
|
617
636
|
// Wide tables scroll their columns on Shift+Left/Right, the way a chart pans,
|
|
618
637
|
// and on Ctrl+Left/Right where the OS leaves those alone (macOS takes them to
|
|
@@ -37,6 +37,7 @@ import { useToastHost } from "../ui/toast";
|
|
|
37
37
|
import { VERSION } from "../version";
|
|
38
38
|
import { Button } from "./ui/button";
|
|
39
39
|
import { Checkbox } from "./ui/checkbox";
|
|
40
|
+
import { FRAMED_TEXTAREA_DESKTOP_STYLE } from "./ui/fields";
|
|
40
41
|
import { DialogFrame } from "./ui/frame";
|
|
41
42
|
import { TERMINAL_MESSAGE_KEYS } from "./textarea-keys";
|
|
42
43
|
|
|
@@ -217,7 +218,7 @@ function FeedbackDialog({
|
|
|
217
218
|
flexGrow={1}
|
|
218
219
|
wrapText
|
|
219
220
|
{...(nativePaneChrome
|
|
220
|
-
? { style:
|
|
221
|
+
? { style: FRAMED_TEXTAREA_DESKTOP_STYLE, onKeyDown: sendOnModifiedEnter }
|
|
221
222
|
: { keyBindings: TERMINAL_MESSAGE_KEYS, onSubmit: () => { void send(); } })}
|
|
222
223
|
onInput={(value: string) => {
|
|
223
224
|
messageValueRef.current = value;
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
import type { CommandBarFieldValue, CommandBarWorkflowField } from "../command-bar/workflow/types";
|
|
20
20
|
import { TERMINAL_MESSAGE_KEYS } from "../textarea-keys";
|
|
21
21
|
import { Checkbox } from "../ui/checkbox";
|
|
22
|
-
import { FieldLabel, NumberField, TextField } from "../ui/fields";
|
|
22
|
+
import { FieldLabel, FRAMED_TEXTAREA_DESKTOP_STYLE, NumberField, TextField } from "../ui/fields";
|
|
23
23
|
import { SelectField, type SelectFieldHandle } from "../ui/select-field";
|
|
24
24
|
import { FORM_TEXTAREA_ROWS } from "./model";
|
|
25
25
|
|
|
@@ -132,7 +132,7 @@ function FormTextarea({
|
|
|
132
132
|
flexGrow={1}
|
|
133
133
|
wrapText
|
|
134
134
|
{...(desktop
|
|
135
|
-
? { style:
|
|
135
|
+
? { style: FRAMED_TEXTAREA_DESKTOP_STYLE, onKeyDown: submitOnModifiedEnter }
|
|
136
136
|
: { keyBindings: TERMINAL_MESSAGE_KEYS, onSubmit: onSubmitField })}
|
|
137
137
|
onInput={(nextValue: string) => onChange(nextValue)}
|
|
138
138
|
/>
|
|
@@ -32,6 +32,7 @@ import { contextMenuDivider, type ContextMenuItem } from "../../types/context-me
|
|
|
32
32
|
import { useKeybindings } from "../../app/keybindings";
|
|
33
33
|
import { useDialogState } from "../../ui/dialog";
|
|
34
34
|
import { getShortcutDisplayMode } from "../../utils/shortcut-labels";
|
|
35
|
+
import { fireAndForget } from "../../utils/fire-and-forget";
|
|
35
36
|
import {
|
|
36
37
|
inputCaptureAllowsPaneManagementShortcut,
|
|
37
38
|
modalSurfaceOwnsKey,
|
|
@@ -142,7 +143,7 @@ export function DetachedPaneShell({ pluginRegistry, desktopWindowBridge }: Detac
|
|
|
142
143
|
if (takeDoubleEscapeClose(doubleEscapeState, desktopWindowBridge.paneId, Date.now())) {
|
|
143
144
|
event.preventDefault();
|
|
144
145
|
event.stopPropagation();
|
|
145
|
-
if (!locked)
|
|
146
|
+
if (!locked) fireAndForget(desktopWindowBridge.closeDetachedPane?.(desktopWindowBridge.paneId), "desktop.closeDetachedPane");
|
|
146
147
|
}
|
|
147
148
|
return;
|
|
148
149
|
}
|
|
@@ -170,7 +171,7 @@ export function DetachedPaneShell({ pluginRegistry, desktopWindowBridge }: Detac
|
|
|
170
171
|
pluginRegistry.notify({ body: "Pane is locked. Unlock it in pane settings.", type: "info" });
|
|
171
172
|
return;
|
|
172
173
|
}
|
|
173
|
-
|
|
174
|
+
fireAndForget(desktopWindowBridge.closeDetachedPane?.(desktopWindowBridge.paneId), "desktop.closeDetachedPane");
|
|
174
175
|
}, [desktopWindowBridge, locked, pluginRegistry]);
|
|
175
176
|
|
|
176
177
|
const startWindowDrag = useCallback(() => {
|
|
@@ -212,7 +213,7 @@ export function DetachedPaneShell({ pluginRegistry, desktopWindowBridge }: Detac
|
|
|
212
213
|
}, [desktopWindowBridge.paneId, focusPane, pluginRegistry]);
|
|
213
214
|
|
|
214
215
|
const dockPane = desktopWindowBridge.dockDetachedPane
|
|
215
|
-
? () => {
|
|
216
|
+
? () => { fireAndForget(desktopWindowBridge.dockDetachedPane?.(desktopWindowBridge.paneId), "desktop.dockDetachedPane"); }
|
|
216
217
|
: null;
|
|
217
218
|
|
|
218
219
|
/** The same menu as a pane in the main window, minus what a window cannot do. */
|
|
@@ -428,9 +429,11 @@ export function DetachedPaneShell({ pluginRegistry, desktopWindowBridge }: Detac
|
|
|
428
429
|
component={paneDef.component}
|
|
429
430
|
paneId={instance.instanceId}
|
|
430
431
|
paneType={instance.paneId}
|
|
432
|
+
title={title}
|
|
431
433
|
focused={focused}
|
|
432
434
|
width={bodyWidth}
|
|
433
435
|
height={bodyHeight}
|
|
436
|
+
closePane={closePane}
|
|
434
437
|
/>
|
|
435
438
|
</PaneHeaderTabsProvider>
|
|
436
439
|
</PaneBodyFrame>
|
|
@@ -7,6 +7,7 @@ import { useThemeColors } from "../../../theme/theme-context";
|
|
|
7
7
|
import { PaneKeyboardScrollController } from "../../../state/pane-scroll-registry";
|
|
8
8
|
import type { PaneDef } from "../../../types/plugin";
|
|
9
9
|
import { Box } from "../../../ui";
|
|
10
|
+
import { PaneErrorBoundary } from "./error-boundary";
|
|
10
11
|
|
|
11
12
|
// Under GLOOMBERB_PERF_TRACE every pane commit is reported by pane, which is
|
|
12
13
|
// how a store update that fans out to the whole layout gets attributed. The
|
|
@@ -29,29 +30,39 @@ interface PaneContentProps {
|
|
|
29
30
|
component: PaneDef["component"];
|
|
30
31
|
paneId: string;
|
|
31
32
|
paneType: string;
|
|
33
|
+
/** The header's title, named by the failure card when the pane throws. */
|
|
34
|
+
title: string;
|
|
32
35
|
focused: boolean;
|
|
33
36
|
width: number;
|
|
34
37
|
height: number;
|
|
35
38
|
/** False while the pane is covered on screen; its streams drop to the off-screen cadence. */
|
|
36
39
|
inView?: boolean;
|
|
40
|
+
/** Passed to the pane as `close` (floating panes). */
|
|
37
41
|
onClose?: (paneId: string) => void;
|
|
42
|
+
/** Takes the pane out of its layout; the failure card offers it. Keep it stable: the content is memoized. */
|
|
43
|
+
closePane?: (paneId: string) => void;
|
|
38
44
|
}
|
|
39
45
|
|
|
40
46
|
export const PaneContent = memo(function PaneContent({
|
|
41
47
|
component: Component,
|
|
42
48
|
paneId,
|
|
43
49
|
paneType,
|
|
50
|
+
title,
|
|
44
51
|
focused,
|
|
45
52
|
width,
|
|
46
53
|
height,
|
|
47
54
|
inView = true,
|
|
48
55
|
onClose,
|
|
56
|
+
closePane,
|
|
49
57
|
}: PaneContentProps) {
|
|
50
58
|
useAppLanguage();
|
|
51
59
|
useThemeColors();
|
|
52
60
|
const close = useCallback(() => {
|
|
53
61
|
onClose?.(paneId);
|
|
54
62
|
}, [onClose, paneId]);
|
|
63
|
+
const closeFailedPane = useCallback(() => {
|
|
64
|
+
closePane?.(paneId);
|
|
65
|
+
}, [closePane, paneId]);
|
|
55
66
|
|
|
56
67
|
return (
|
|
57
68
|
<PaneInstanceProvider paneId={paneId}>
|
|
@@ -67,16 +78,18 @@ export const PaneContent = memo(function PaneContent({
|
|
|
67
78
|
overflow="hidden"
|
|
68
79
|
data-gloom-role="pane-content"
|
|
69
80
|
>
|
|
70
|
-
<
|
|
71
|
-
<
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
81
|
+
<PaneErrorBoundary paneType={paneType} title={title} onClose={closePane ? closeFailedPane : undefined}>
|
|
82
|
+
<PaneRenderTrace paneId={paneId} paneType={paneType}>
|
|
83
|
+
<Component
|
|
84
|
+
paneId={paneId}
|
|
85
|
+
paneType={paneType}
|
|
86
|
+
focused={focused}
|
|
87
|
+
width={width}
|
|
88
|
+
height={height}
|
|
89
|
+
close={onClose ? close : undefined}
|
|
90
|
+
/>
|
|
91
|
+
</PaneRenderTrace>
|
|
92
|
+
</PaneErrorBoundary>
|
|
80
93
|
</Box>
|
|
81
94
|
</PaneInViewProvider>
|
|
82
95
|
</PaneInstanceProvider>
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { Component, type ErrorInfo, type ReactNode } from "react";
|
|
2
|
+
import { tf } from "../../../i18n";
|
|
3
|
+
import { getSharedRegistry } from "../../../plugins/registry/shared";
|
|
4
|
+
import { reportCrash } from "../../../telemetry/crash-reports";
|
|
5
|
+
import { debugLog } from "../../../utils/debug-log";
|
|
6
|
+
import { Button } from "../../ui/button";
|
|
7
|
+
import { PaneStatusBody } from "../../ui/status";
|
|
8
|
+
|
|
9
|
+
const MAX_MESSAGE_LENGTH = 200;
|
|
10
|
+
|
|
11
|
+
/** The first line of what was thrown, clipped: the card has one line for it. */
|
|
12
|
+
function failureMessage(error: unknown): string {
|
|
13
|
+
const raw = error instanceof Error
|
|
14
|
+
? error.message || error.name
|
|
15
|
+
: typeof error === "string" ? error : String(error);
|
|
16
|
+
const line = raw.split("\n").find((part) => part.trim())?.trim() || "Unknown error";
|
|
17
|
+
return line.length > MAX_MESSAGE_LENGTH ? `${line.slice(0, MAX_MESSAGE_LENGTH - 3)}...` : line;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function failureKey(error: unknown): string {
|
|
21
|
+
return error instanceof Error ? `${error.name}\n${error.message}` : String(error);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface PaneErrorBoundaryProps {
|
|
25
|
+
paneType: string;
|
|
26
|
+
title: string;
|
|
27
|
+
/** Takes the pane out of the layout; without it the card offers Reload only. */
|
|
28
|
+
onClose?: () => void;
|
|
29
|
+
children: ReactNode;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
interface PaneErrorBoundaryState {
|
|
33
|
+
error: { value: unknown } | null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Keeps a pane that throws while rendering inside its own frame: the pane body
|
|
38
|
+
* becomes a failure card with Reload and Close, and every other pane, the
|
|
39
|
+
* command bar and the layout keep working. The pane's header stays outside, so
|
|
40
|
+
* it can still be moved or closed from its menu.
|
|
41
|
+
*
|
|
42
|
+
* Only render errors reach it. Event handlers, effects and async work fail the
|
|
43
|
+
* way they always have.
|
|
44
|
+
*/
|
|
45
|
+
export class PaneErrorBoundary extends Component<PaneErrorBoundaryProps, PaneErrorBoundaryState> {
|
|
46
|
+
override state: PaneErrorBoundaryState = { error: null };
|
|
47
|
+
private reportedKey: string | null = null;
|
|
48
|
+
|
|
49
|
+
static getDerivedStateFromError(error: unknown): PaneErrorBoundaryState {
|
|
50
|
+
return { error: { value: error } };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
override componentDidCatch(error: unknown, errorInfo: ErrorInfo): void {
|
|
54
|
+
// A pane that fails again after Reload, or re-renders its card, is still
|
|
55
|
+
// the same failure: reported once.
|
|
56
|
+
const key = failureKey(error);
|
|
57
|
+
if (key === this.reportedKey) return;
|
|
58
|
+
this.reportedKey = key;
|
|
59
|
+
const { paneType } = this.props;
|
|
60
|
+
const plugin = getSharedRegistry()?.getPanePluginId(paneType);
|
|
61
|
+
reportCrash(error, { kind: "render", pane: paneType, plugin, componentStack: errorInfo.componentStack });
|
|
62
|
+
// Logged under the owning plugin, so the Plugins pane counts it as one of its errors.
|
|
63
|
+
debugLog.createLogger(plugin ?? "pane").error(`Pane ${paneType} stopped rendering: ${failureMessage(error)}`, {
|
|
64
|
+
componentStack: errorInfo.componentStack,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
private readonly reload = () => {
|
|
69
|
+
this.setState({ error: null });
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
override render(): ReactNode {
|
|
73
|
+
const { error } = this.state;
|
|
74
|
+
if (!error) return this.props.children;
|
|
75
|
+
return (
|
|
76
|
+
<FallbackGuard>
|
|
77
|
+
<PaneStatusBody
|
|
78
|
+
error={failureMessage(error.value)}
|
|
79
|
+
errorTitle={tf("{title} stopped working.", { title: this.props.title })}
|
|
80
|
+
actions={(
|
|
81
|
+
<>
|
|
82
|
+
<Button label="Reload pane" variant="primary" compact onPress={this.reload} />
|
|
83
|
+
{this.props.onClose && <Button label="Close pane" variant="secondary" compact onPress={this.props.onClose} />}
|
|
84
|
+
</>
|
|
85
|
+
)}
|
|
86
|
+
/>
|
|
87
|
+
</FallbackGuard>
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** A card that cannot render leaves the body empty rather than taking the app down with it. */
|
|
93
|
+
class FallbackGuard extends Component<{ children: ReactNode }, { failed: boolean }> {
|
|
94
|
+
override state = { failed: false };
|
|
95
|
+
|
|
96
|
+
static getDerivedStateFromError(): { failed: boolean } {
|
|
97
|
+
return { failed: true };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
override render(): ReactNode {
|
|
101
|
+
return this.state.failed ? null : this.props.children;
|
|
102
|
+
}
|
|
103
|
+
}
|