gloomberb 0.11.2 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -4
- package/README.zh-CN.md +4 -2
- package/package.json +28 -1
- package/src/api-client/auth.ts +10 -0
- package/src/api-client/data.ts +108 -1
- package/src/api-client/index.test.ts +127 -0
- package/src/api-client/index.ts +134 -1
- package/src/api-client/normalizers.ts +39 -0
- package/src/api-client/paths.ts +85 -1
- package/src/api-client/types.ts +220 -0
- package/src/app/pane-runtime/index.tsx +15 -12
- package/src/app/pane-runtime/layout-placement.test.ts +27 -0
- package/src/app/pane-runtime/layout-placement.ts +13 -0
- package/src/app/pane-runtime/plugin-bindings.ts +62 -0
- package/src/app.tsx +60 -18
- package/src/architecture/browser-entry-graph.test.ts +96 -0
- package/src/brokers/profile-form.test.ts +25 -27
- package/src/brokers/test-broker.ts +68 -0
- package/src/capabilities/chart-series.ts +3 -2
- package/src/cli/commands/market.ts +2 -2
- package/src/cli/commands/plugins.ts +39 -11
- package/src/cli/desktop-pane-shot.ts +285 -16
- package/src/cli/index.ts +1 -1
- package/src/cli/pane-functions/capabilities.ts +61 -31
- package/src/cli/pane-functions/catalog.ts +16 -4
- package/src/cli/pane-functions/discovery.ts +1 -0
- package/src/cli/pane-functions/headless.test.ts +247 -0
- package/src/cli/pane-functions/headless.ts +423 -0
- package/src/cli/pane-functions/index.test.ts +9 -0
- package/src/cli/pane-functions/index.ts +6 -2
- package/src/cli/pane-functions/options.ts +27 -2
- package/src/cli/pane-functions/report.ts +4 -0
- package/src/cli/pane-functions/resolver.ts +26 -8
- package/src/cli/pane-functions/screenshot.test.ts +76 -0
- package/src/cli/pane-functions/screenshot.ts +236 -20
- package/src/cli/registry.ts +0 -22
- package/src/cli/restore-plugins.ts +34 -0
- package/src/cli/result.ts +7 -10
- package/src/components/chart/{static/chart → composite}/axis-overlays.test.tsx +3 -3
- package/src/components/chart/{static/chart → composite}/axis-overlays.tsx +6 -11
- package/src/components/chart/{static/chart → composite}/bitmap.ts +17 -3
- package/src/components/chart/composite/composite-chart.test.tsx +68 -20
- package/src/components/chart/composite/composite-chart.tsx +301 -204
- package/src/components/chart/composite/format.ts +8 -2
- package/src/components/chart/composite/interactions.test.ts +68 -102
- package/src/components/chart/composite/interactions.ts +214 -264
- package/src/components/chart/composite/price-axis-labels.test.ts +21 -0
- package/src/components/chart/{price-axis-labels.tsx → composite/price-axis-labels.tsx} +9 -4
- package/src/components/chart/composite/scene.ts +57 -3
- package/src/components/chart/composite/text-renderer.ts +3 -2
- package/src/components/chart/composite/time-scale.ts +138 -57
- package/src/components/chart/composite/types.ts +25 -1
- package/src/components/chart/core/data.ts +9 -13
- package/src/components/chart/core/date-window.ts +7 -1
- package/src/components/chart/core/pointer.ts +3 -0
- package/src/components/chart/core/types.ts +0 -45
- package/src/components/chart/native/chart-rasterizer.ts +0 -1
- package/src/components/chart/native/kitty/index.test.ts +0 -188
- package/src/components/chart/native/raster/crosshair.ts +6 -5
- package/src/components/chart/native/raster/primitives.ts +0 -23
- package/src/components/chart/native/renderer-selection.ts +81 -31
- package/src/components/chart/static/{chart/surface.test.tsx → chart-surface.test.tsx} +28 -80
- package/src/components/chart/static/chart-surface.tsx +150 -0
- package/src/components/chart/static/index.ts +8 -0
- package/src/components/chart/static/multi-line-chart-surface.tsx +51 -166
- package/src/components/chart/static/scatter-chart-surface.test.ts +30 -0
- package/src/components/chart/static/scatter-chart-surface.tsx +135 -34
- package/src/components/chart/static/series.ts +49 -0
- package/src/components/command-bar/action-runtime.ts +1 -3
- package/src/components/command-bar/assist/model.test.ts +17 -2
- package/src/components/command-bar/assist/model.ts +40 -9
- package/src/components/command-bar/commands/direct/index.ts +1 -1
- package/src/components/command-bar/commands/direct/runtime.ts +1 -1
- package/src/components/command-bar/commands/registry.ts +0 -11
- package/src/components/command-bar/helpers.test.ts +2 -2
- package/src/components/command-bar/helpers.ts +2 -6
- package/src/components/command-bar/keyboard-shortcuts.ts +0 -11
- package/src/components/command-bar/list/badge.test.ts +54 -0
- package/src/components/command-bar/list/badge.ts +62 -0
- package/src/components/command-bar/list/model.test.ts +103 -0
- package/src/components/command-bar/list/model.ts +61 -4
- package/src/components/command-bar/list/view.test.tsx +113 -0
- package/src/components/command-bar/list/view.tsx +147 -131
- package/src/components/command-bar/pane-templates/workflow.ts +1 -1
- package/src/components/command-bar/panel/body.tsx +51 -65
- package/src/components/command-bar/panel/index.tsx +48 -13
- package/src/components/command-bar/panel/layout.test.ts +139 -0
- package/src/components/command-bar/panel/layout.ts +65 -28
- package/src/components/command-bar/panel/native-surface.ts +24 -0
- package/src/components/command-bar/panel/prompt-binding.ts +54 -0
- package/src/components/command-bar/panel/runtime.ts +6 -3
- package/src/components/command-bar/panel/state.ts +41 -7
- package/src/components/command-bar/panel/types.ts +7 -1
- package/src/components/command-bar/routes/root/provider-search.ts +34 -15
- package/src/components/command-bar/routes/root/results.test.ts +161 -0
- package/src/components/command-bar/routes/root/results.ts +30 -28
- package/src/components/command-bar/routes/root/runtime.ts +37 -20
- package/src/components/command-bar/routes/root/search-providers.test.tsx +224 -0
- package/src/components/command-bar/routes/root/search-providers.ts +205 -0
- package/src/components/command-bar/routes/root/selection.ts +1 -12
- package/src/components/command-bar/routes/root/shortcuts.test.ts +8 -8
- package/src/components/command-bar/routes/ticker-search/actions.ts +10 -9
- package/src/components/command-bar/routes/ticker-search/results.test.ts +54 -1
- package/src/components/command-bar/routes/ticker-search/results.ts +60 -19
- package/src/components/command-bar/routes/ticker-search/route.ts +1 -0
- package/src/components/command-bar/routing/actions.ts +1 -81
- package/src/components/command-bar/routing/launch-request.ts +1 -1
- package/src/components/command-bar/routing/list-state.ts +6 -21
- package/src/components/command-bar/selection-runtime.ts +1 -1
- package/src/components/command-bar/surface/assist.test.tsx +14 -10
- package/src/components/command-bar/surface/environment.ts +8 -1
- package/src/components/command-bar/surface/index.test.tsx +84 -68
- package/src/components/command-bar/surface/index.tsx +33 -36
- package/src/components/command-bar/surface/test-harness.tsx +15 -3
- package/src/components/command-bar/theme-picker.tsx +43 -15
- package/src/components/command-bar/view-model.test.ts +53 -8
- package/src/components/command-bar/view-model.ts +43 -14
- package/src/components/command-bar/workflow/tickers.ts +1 -0
- package/src/components/command-bar/workflow/types.ts +1 -1
- package/src/components/data-table/export.test.ts +21 -0
- package/src/components/data-table/export.ts +21 -0
- package/src/components/data-table/view.test.tsx +45 -6
- package/src/components/data-table/view.tsx +55 -9
- package/src/components/index.ts +10 -2
- package/src/components/input-search-bar.test.tsx +36 -2
- package/src/components/input-search-bar.tsx +18 -1
- package/src/components/layout/header.test.tsx +57 -10
- package/src/components/layout/header.tsx +292 -149
- package/src/components/layout/market-summary.test.ts +81 -0
- package/src/components/layout/market-summary.ts +109 -0
- package/src/components/layout/shell/chrome.ts +96 -1
- package/src/components/layout/shell/index.tsx +11 -3
- package/src/components/layout/shell/menu.ts +9 -0
- package/src/components/layout/shell/pane/actions.ts +29 -0
- package/src/components/layout/shell/pane/management-shortcuts.ts +5 -0
- package/src/components/layout/shell/shortcuts.ts +3 -0
- package/src/components/layout/status-bar.test.tsx +9 -8
- package/src/components/layout/status-bar.tsx +85 -54
- package/src/components/onboarding/onboarding-frame.tsx +2 -26
- package/src/components/price-sparkline/index.ts +61 -34
- package/src/components/price-sparkline/view.tsx +1 -1
- package/src/components/sign-in-gate.test.tsx +128 -0
- package/src/components/sign-in-gate.tsx +149 -0
- package/src/components/speedometer-gauge/desktop.tsx +2 -12
- package/src/components/ticker/badge/list.tsx +17 -3
- package/src/components/ticker/list-table-view.tsx +6 -3
- package/src/components/ui/data-table/index.tsx +22 -4
- package/src/components/ui/data-table/opentui/index.tsx +165 -120
- package/src/components/ui/frame.tsx +28 -0
- package/src/components/ui/index.ts +3 -0
- package/src/components/ui/native-select.tsx +20 -10
- package/src/components/ui/select-button.tsx +138 -0
- package/src/components/ui/status.tsx +2 -2
- package/src/components/ui/table-layout.ts +1 -1
- package/src/components/use-double-click-activation.ts +7 -3
- package/src/core/app-services.ts +3 -3
- package/src/data/config/chart-settings.ts +4 -4
- package/src/data/config/layout.ts +12 -6
- package/src/data/config/store/index.test.ts +97 -0
- package/src/data/config/store/migrations.ts +41 -0
- package/src/data/config/store/normalize.ts +5 -3
- package/src/i18n/es.ts +6 -2
- package/src/i18n/ja.ts +6 -2
- package/src/i18n/ko.ts +6 -2
- package/src/i18n/zh-cn.ts +6 -2
- package/src/i18n/zh-tw.ts +6 -2
- package/src/layout-marketplace/gallery-terminal.tsx +126 -96
- package/src/layout-marketplace/gallery.test.tsx +65 -1
- package/src/layout-marketplace/pane-imagery.ts +1 -0
- package/src/layout-marketplace/payload.test.ts +17 -0
- package/src/layout-marketplace/payload.ts +40 -5
- package/src/market-data/coordinator/index.ts +3 -2
- package/src/market-data/coordinator/quotes.ts +173 -66
- package/src/market-data/coordinator/subscriptions.test.ts +215 -37
- package/src/pane-settings.ts +1 -1
- package/src/plugins/builtin/analytics/pane-model.ts +1 -1
- package/src/plugins/builtin/analytics/view.tsx +1 -1
- package/src/plugins/builtin/broker-manager/index.test.tsx +3 -2
- package/src/plugins/builtin/broker-manager/model.test.ts +2 -2
- package/src/plugins/builtin/chart-composer/catalog-inventory.ts +16 -2
- package/src/plugins/builtin/chart-composer/cli-options.ts +12 -9
- package/src/plugins/builtin/chart-composer/pane.tsx +22 -8
- package/src/plugins/builtin/chart-composer/settings.ts +2 -13
- package/src/plugins/builtin/chat/content/composer.tsx +8 -4
- package/src/plugins/builtin/cloud/auth-dialog.tsx +14 -228
- package/src/plugins/builtin/cloud/auth-form.tsx +277 -0
- package/src/plugins/builtin/cloud/plugin.tsx +1 -0
- package/src/plugins/builtin/composite-plugins.ts +16 -1
- package/src/plugins/builtin/correlation/relationship/model.ts +1 -1
- package/src/plugins/builtin/correlation/relationship/pane.tsx +2 -6
- package/src/plugins/builtin/correlation/relationship/view-model.ts +2 -2
- package/src/plugins/builtin/credit-conditions/index.test.tsx +12 -6
- package/src/plugins/builtin/credit-conditions/index.tsx +2 -21
- package/src/plugins/builtin/dividend-yield/index.tsx +1 -0
- package/src/plugins/builtin/dividend-yield/pane.tsx +1 -1
- package/src/plugins/builtin/earnings/index.tsx +1 -0
- package/src/plugins/builtin/earnings-calls/data.ts +223 -0
- package/src/plugins/builtin/earnings-calls/format.ts +49 -0
- package/src/plugins/builtin/earnings-calls/index.tsx +69 -0
- package/src/plugins/builtin/earnings-calls/pane.tsx +756 -0
- package/src/plugins/builtin/earnings-calls/prose.test.ts +36 -0
- package/src/plugins/builtin/earnings-calls/prose.ts +59 -0
- package/src/plugins/builtin/earnings-calls/transcript-view.tsx +334 -0
- package/src/plugins/builtin/econ/detail-view.tsx +1 -2
- package/src/plugins/builtin/econ/fred-series-map.ts +16 -1
- package/src/plugins/builtin/econ/index.tsx +3 -1
- package/src/plugins/builtin/econ-statistics/cache.ts +4 -0
- package/src/plugins/builtin/econ-statistics/client.ts +92 -0
- package/src/plugins/builtin/econ-statistics/defs.ts +66 -0
- package/src/plugins/builtin/econ-statistics/detail.tsx +154 -0
- package/src/plugins/builtin/econ-statistics/headless.test.ts +54 -0
- package/src/plugins/builtin/econ-statistics/headless.ts +171 -0
- package/src/plugins/builtin/econ-statistics/index.tsx +54 -0
- package/src/plugins/builtin/econ-statistics/pane.tsx +356 -0
- package/src/plugins/builtin/econ-statistics/stats.ts +522 -0
- package/src/plugins/builtin/econ-statistics/transform.test.ts +86 -0
- package/src/plugins/builtin/econ-statistics/transform.ts +85 -0
- package/src/plugins/builtin/econ-statistics/trend.ts +57 -0
- package/src/plugins/builtin/econ-statistics/view.ts +90 -0
- package/src/plugins/builtin/fear-greed/charts.tsx +7 -18
- package/src/plugins/builtin/fear-greed/data.ts +6 -1
- package/src/plugins/builtin/futures/index.tsx +1 -0
- package/src/plugins/builtin/fx-matrix/index.tsx +1 -0
- package/src/plugins/builtin/help/index.tsx +4 -0
- package/src/plugins/builtin/holders/index.tsx +1 -0
- package/src/plugins/builtin/insider/index.tsx +1 -0
- package/src/plugins/builtin/ipo-calendar/index.tsx +1 -0
- package/src/plugins/builtin/kelly-sizer/pane.tsx +1 -1
- package/src/plugins/builtin/kelly-sizer/sections.tsx +2 -3
- package/src/plugins/builtin/market-halts/index.tsx +1 -0
- package/src/plugins/builtin/market-movers/index.tsx +1 -0
- package/src/plugins/builtin/market-valuation/align.ts +122 -0
- package/src/plugins/builtin/market-valuation/cache.ts +32 -0
- package/src/plugins/builtin/market-valuation/chart-projection.ts +217 -0
- package/src/plugins/builtin/market-valuation/chart-series.ts +89 -0
- package/src/plugins/builtin/market-valuation/client.test.ts +141 -0
- package/src/plugins/builtin/market-valuation/client.ts +116 -0
- package/src/plugins/builtin/market-valuation/defs.ts +251 -0
- package/src/plugins/builtin/market-valuation/detail.tsx +159 -0
- package/src/plugins/builtin/market-valuation/headless.test.ts +58 -0
- package/src/plugins/builtin/market-valuation/headless.ts +170 -0
- package/src/plugins/builtin/market-valuation/index.tsx +64 -0
- package/src/plugins/builtin/market-valuation/indicators.ts +422 -0
- package/src/plugins/builtin/market-valuation/model.test.ts +350 -0
- package/src/plugins/builtin/market-valuation/model.ts +8 -0
- package/src/plugins/builtin/market-valuation/pane.test.tsx +247 -0
- package/src/plugins/builtin/market-valuation/pane.tsx +344 -0
- package/src/plugins/builtin/market-valuation/series.ts +12 -0
- package/src/plugins/builtin/market-valuation/settings.ts +38 -0
- package/src/plugins/builtin/market-valuation/sources.ts +130 -0
- package/src/plugins/builtin/market-valuation/trend.ts +89 -0
- package/src/plugins/builtin/market-valuation/view.ts +137 -0
- package/src/plugins/builtin/market-valuation/zone-scale/desktop.tsx +123 -0
- package/src/plugins/builtin/market-valuation/zone-scale/index.tsx +12 -0
- package/src/plugins/builtin/market-valuation/zone-scale/model.ts +60 -0
- package/src/plugins/builtin/market-valuation/zone-scale/terminal.tsx +94 -0
- package/src/plugins/builtin/news/wire/breaking/filters.test.ts +99 -0
- package/src/plugins/builtin/news/wire/breaking/filters.ts +110 -0
- package/src/plugins/builtin/news/wire/breaking/notifications.test.ts +157 -53
- package/src/plugins/builtin/news/wire/breaking/notifications.ts +91 -25
- package/src/plugins/builtin/news/wire/index.tsx +31 -44
- package/src/plugins/builtin/options/analytics.test.ts +83 -0
- package/src/plugins/builtin/options/analytics.ts +110 -0
- package/src/plugins/builtin/options/index.tsx +18 -2
- package/src/plugins/builtin/options/table.ts +121 -51
- package/src/plugins/builtin/options/types.ts +22 -15
- package/src/plugins/builtin/options/view.test.tsx +53 -1
- package/src/plugins/builtin/options/view.tsx +92 -41
- package/src/plugins/builtin/plugin-marketplace/feed.ts +80 -0
- package/src/plugins/builtin/plugin-marketplace/index.tsx +31 -0
- package/src/plugins/builtin/plugin-marketplace/model.test.ts +200 -0
- package/src/plugins/builtin/plugin-marketplace/model.ts +204 -0
- package/src/plugins/builtin/plugin-marketplace/pane.tsx +385 -0
- package/src/plugins/builtin/plugin-marketplace/store.ts +46 -0
- package/src/plugins/builtin/plugin-module.test.ts +2 -4
- package/src/plugins/builtin/plugin-module.ts +9 -8
- package/src/plugins/builtin/portfolio-list/index.tsx +1 -0
- package/src/plugins/builtin/research/index.tsx +4 -0
- package/src/plugins/builtin/research-search/command-bar-search.test.ts +81 -0
- package/src/plugins/builtin/research-search/command-bar-search.ts +175 -0
- package/src/plugins/builtin/research-search/data.ts +109 -0
- package/src/plugins/builtin/research-search/document-view.test.tsx +75 -0
- package/src/plugins/builtin/research-search/document-view.tsx +254 -0
- package/src/plugins/builtin/research-search/filter-bar.tsx +62 -0
- package/src/plugins/builtin/research-search/focus-handoff.ts +47 -0
- package/src/plugins/builtin/research-search/index.tsx +85 -0
- package/src/plugins/builtin/research-search/model.test.ts +40 -0
- package/src/plugins/builtin/research-search/model.ts +291 -0
- package/src/plugins/builtin/research-search/pane.test.tsx +241 -0
- package/src/plugins/builtin/research-search/pane.tsx +678 -0
- package/src/plugins/builtin/research-search/saved-view.tsx +171 -0
- package/src/plugins/builtin/research-search/snippet-text.tsx +35 -0
- package/src/plugins/builtin/research-search/snippet.test.ts +78 -0
- package/src/plugins/builtin/research-search/snippet.ts +134 -0
- package/src/plugins/builtin/scanner/flow-model.test.ts +11 -1
- package/src/plugins/builtin/scanner/flow-model.ts +29 -1
- package/src/plugins/builtin/scanner/flow-pane.tsx +78 -22
- package/src/plugins/builtin/scanner/index.ts +2 -0
- package/src/plugins/builtin/sec/index.tsx +1 -0
- package/src/plugins/builtin/sectors/index.tsx +1 -0
- package/src/plugins/builtin/shared/series-cache.ts +93 -0
- package/src/plugins/builtin/short-interest/index.tsx +1 -0
- package/src/plugins/builtin/short-interest/pane.tsx +1 -1
- package/src/plugins/builtin/thirteenf/index.tsx +1 -0
- package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +3 -5
- package/src/plugins/builtin/ticker-detail/index.tsx +2 -14
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +1 -1
- package/src/plugins/builtin/treasury-auctions/index.tsx +1 -0
- package/src/plugins/builtin/volatility/index.tsx +1 -1
- package/src/plugins/builtin/world-indices/index.tsx +1 -0
- package/src/plugins/builtin/world-venue-map/index.ts +27 -0
- package/src/plugins/builtin/world-venue-map/map.desktop.test.tsx +106 -0
- package/src/plugins/builtin/world-venue-map/map.tsx +481 -0
- package/src/plugins/builtin/world-venue-map/model.test.ts +85 -0
- package/src/plugins/builtin/world-venue-map/model.ts +268 -0
- package/src/plugins/builtin/world-venue-map/pane.tsx +300 -0
- package/src/plugins/builtin/world-venue-map/world-outlines.ts +2 -0
- package/src/plugins/builtin/yield-curve/index.tsx +1 -1
- package/src/plugins/bundle.test.ts +109 -0
- package/src/plugins/bundle.ts +139 -0
- package/src/plugins/catalog-backend.ts +6 -44
- package/src/plugins/catalog-browser.test.ts +1 -0
- package/src/plugins/catalog-browser.ts +12 -0
- package/src/plugins/catalog-manifest.test.ts +43 -0
- package/src/plugins/catalog-manifest.ts +92 -0
- package/src/plugins/catalog-ui.ts +20 -4
- package/src/plugins/catalog.ts +9 -2
- package/src/plugins/current-target.ts +28 -0
- package/src/plugins/host-contract.ts +37 -0
- package/src/plugins/host-link.ts +158 -0
- package/src/plugins/host-modules.ts +61 -0
- package/src/plugins/loader.ts +41 -22
- package/src/plugins/ownership.ts +1 -0
- package/src/plugins/prediction-markets/index.tsx +1 -0
- package/src/plugins/registry/context.ts +3 -0
- package/src/plugins/registry/contributions.ts +27 -0
- package/src/plugins/registry/index.test.ts +25 -0
- package/src/plugins/registry/index.ts +8 -0
- package/src/plugins/registry/pane-settings.test.ts +53 -0
- package/src/plugins/registry/pane-settings.ts +29 -3
- package/src/plugins/seed.test.ts +83 -0
- package/src/plugins/seed.ts +80 -0
- package/src/public/broker.ts +31 -0
- package/src/public/market-data.ts +9 -0
- package/src/public/pane-hooks.ts +57 -0
- package/src/public/public-api.test.ts +285 -0
- package/src/public/react.ts +62 -0
- package/src/public/test-support.ts +23 -0
- package/src/public/time-series.ts +8 -0
- package/src/public/utils.ts +77 -0
- package/src/remote/layout-helpers.ts +6 -8
- package/src/remote/resources.ts +2 -0
- package/src/remote/schema.ts +1 -0
- package/src/remote/semantic-tree.test.tsx +105 -0
- package/src/remote/semantic-tree.tsx +53 -35
- package/src/renderers/browser/main.tsx +6 -0
- package/src/renderers/browser/ui-host.tsx +11 -0
- package/src/renderers/cloudflare/worker.test.ts +19 -0
- package/src/renderers/cloudflare/worker.ts +1 -1
- package/src/renderers/electrobun/bun/desktop/host-requests.ts +9 -2
- package/src/renderers/electrobun/bun/external-plugins.ts +140 -0
- package/src/renderers/electrobun/bun/index.ts +6 -2
- package/src/renderers/electrobun/shared/protocol.ts +25 -0
- package/src/renderers/electrobun/view/build-assets.ts +0 -1
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +51 -1
- package/src/renderers/electrobun/view/external-plugins.test.ts +45 -0
- package/src/renderers/electrobun/view/external-plugins.ts +63 -0
- package/src/renderers/electrobun/view/host/ascii-text.test.ts +48 -0
- package/src/renderers/electrobun/view/host/ascii-text.ts +11 -1
- package/src/renderers/electrobun/view/host/chart-surface.tsx +38 -32
- package/src/renderers/electrobun/view/host/mouse.ts +16 -2
- package/src/renderers/electrobun/view/main.tsx +27 -2
- package/src/renderers/electrobun/view/styles.css +5 -0
- package/src/renderers/electrobun/view/toast-host.tsx +18 -0
- package/src/renderers/electrobun/view/ui-host.tsx +3 -0
- package/src/renderers/opentui/chart-surface.tsx +5 -1
- package/src/renderers/opentui/host.tsx +20 -2
- package/src/renderers/opentui/interaction-performance.test.ts +79 -0
- package/src/renderers/opentui/interaction-performance.ts +188 -0
- package/src/renderers/opentui/start.tsx +26 -1
- package/src/renderers/opentui/test-utils.tsx +13 -0
- package/src/renderers/opentui/toast-host.tsx +26 -2
- package/src/renderers/opentui/ui-host.tsx +1 -0
- package/src/sources/provider-router/search.test.ts +191 -0
- package/src/sources/provider-router/search.ts +92 -39
- package/src/state/app/context/index.tsx +2 -0
- package/src/state/app/context/selector.test.tsx +33 -1
- package/src/state/hooks/quote-streaming.test.tsx +93 -0
- package/src/state/hooks/quote-streaming.ts +106 -30
- package/src/state/pane-table-export-registry.ts +50 -0
- package/src/theme/color-utils.ts +1 -1
- package/src/theme/colors.ts +50 -0
- package/src/theme/themes.test.ts +15 -2
- package/src/theme/themes.ts +19 -1
- package/src/tickers/search/index.test.ts +26 -0
- package/src/tickers/search/index.ts +42 -17
- package/src/tickers/search/ranking.ts +14 -0
- package/src/time-series/chart-data.test.ts +216 -0
- package/src/time-series/range.ts +12 -0
- package/src/time-series/resolution.test.ts +25 -26
- package/src/time-series/resolution.ts +44 -25
- package/src/time-series/resolve.ts +7 -0
- package/src/time-series/spec.ts +5 -5
- package/src/time-series/types.ts +3 -1
- package/src/time-series/use-chart-resolution.ts +5 -0
- package/src/types/config.ts +123 -3
- package/src/types/data-provider.ts +11 -0
- package/src/types/headless.ts +161 -0
- package/src/types/plugin.ts +104 -20
- package/src/ui/host.tsx +19 -1
- package/src/ui/index.tsx +1 -0
- package/src/ui/toast.tsx +8 -4
- package/src/utils/csv.test.ts +13 -0
- package/src/utils/csv.ts +37 -0
- package/src/utils/format.ts +35 -0
- package/src/utils/fuzzy-search.test.ts +94 -0
- package/src/utils/fuzzy-search.ts +81 -22
- package/src/utils/save-text-file.test.ts +24 -0
- package/src/utils/save-text-file.ts +36 -0
- package/src/utils/shortcut-labels.ts +14 -0
- package/src/components/chart/core/axis-format.ts +0 -157
- package/src/components/chart/core/index.test.ts +0 -1075
- package/src/components/chart/core/projection.ts +0 -357
- package/src/components/chart/core/render-utils.ts +0 -4
- package/src/components/chart/core/renderer.ts +0 -244
- package/src/components/chart/core/scene.ts +0 -180
- package/src/components/chart/core/time-axis.ts +0 -330
- package/src/components/chart/cursor-motion.ts +0 -47
- package/src/components/chart/indicators/types.ts +0 -26
- package/src/components/chart/market-session.ts +0 -176
- package/src/components/chart/multi-line/renderer.test.ts +0 -83
- package/src/components/chart/multi-line/renderer.ts +0 -161
- package/src/components/chart/multi-line/scene.ts +0 -188
- package/src/components/chart/native/raster/layout.ts +0 -129
- package/src/components/chart/native/raster/price-chart.ts +0 -244
- package/src/components/chart/rendering/chart-draw.ts +0 -270
- package/src/components/chart/rendering/geometry.ts +0 -95
- package/src/components/chart/rendering/pixel-buffer.ts +0 -267
- package/src/components/chart/scatter-chart-renderer.test.ts +0 -31
- package/src/components/chart/scatter-chart-renderer.ts +0 -223
- package/src/components/chart/static/chart/surface.tsx +0 -358
- package/src/components/command-bar/routes/root/article-results.test.ts +0 -83
- package/src/components/command-bar/routes/root/article-results.ts +0 -55
- package/src/plugins/builtin/news/wire/article-search.test.ts +0 -72
- package/src/plugins/builtin/news/wire/article-search.ts +0 -140
- package/src/plugins/builtin/substack/api/auth.ts +0 -185
- package/src/plugins/builtin/substack/api/cache.ts +0 -82
- package/src/plugins/builtin/substack/api/loaders.ts +0 -170
- package/src/plugins/builtin/substack/api/store.ts +0 -186
- package/src/plugins/builtin/substack/api/types.ts +0 -42
- package/src/plugins/builtin/substack/api.test.ts +0 -298
- package/src/plugins/builtin/substack/article-detail.tsx +0 -397
- package/src/plugins/builtin/substack/article-stack.tsx +0 -133
- package/src/plugins/builtin/substack/content.ts +0 -478
- package/src/plugins/builtin/substack/feed-tabs.tsx +0 -44
- package/src/plugins/builtin/substack/index.tsx +0 -49
- package/src/plugins/builtin/substack/login-view.tsx +0 -126
- package/src/plugins/builtin/substack/model.test.ts +0 -155
- package/src/plugins/builtin/substack/normalize.ts +0 -343
- package/src/plugins/builtin/substack/pane-footer.ts +0 -52
- package/src/plugins/builtin/substack/pane-state.ts +0 -170
- package/src/plugins/builtin/substack/pane.tsx +0 -547
- package/src/plugins/builtin/substack/read-state.ts +0 -30
- package/src/plugins/builtin/substack/table.ts +0 -111
- package/src/plugins/builtin/substack/types.ts +0 -71
- package/src/plugins/builtin/substack/utils.ts +0 -131
- package/src/plugins/builtin/ticker-detail/data-panes/provider-search.tsx +0 -229
- package/src/plugins/ibkr/account-cache.test.ts +0 -102
- package/src/plugins/ibkr/account-cache.ts +0 -24
- package/src/plugins/ibkr/broker-adapter.ts +0 -286
- package/src/plugins/ibkr/config.test.ts +0 -79
- package/src/plugins/ibkr/config.ts +0 -250
- package/src/plugins/ibkr/dialogs.tsx +0 -40
- package/src/plugins/ibkr/flex/index.test.ts +0 -264
- package/src/plugins/ibkr/flex/index.ts +0 -367
- package/src/plugins/ibkr/flex/statement-client.ts +0 -235
- package/src/plugins/ibkr/fundamental-parser.ts +0 -149
- package/src/plugins/ibkr/gateway/account-loaders.ts +0 -266
- package/src/plugins/ibkr/gateway/account-summary.ts +0 -164
- package/src/plugins/ibkr/gateway/client-lock.ts +0 -154
- package/src/plugins/ibkr/gateway/connection-events.ts +0 -114
- package/src/plugins/ibkr/gateway/connection.ts +0 -152
- package/src/plugins/ibkr/gateway/contracts.ts +0 -132
- package/src/plugins/ibkr/gateway/fundamentals.ts +0 -83
- package/src/plugins/ibkr/gateway/helpers.ts +0 -33
- package/src/plugins/ibkr/gateway/history-requests.ts +0 -158
- package/src/plugins/ibkr/gateway/history.ts +0 -120
- package/src/plugins/ibkr/gateway/instrument-lookup.ts +0 -117
- package/src/plugins/ibkr/gateway/market-data.ts +0 -345
- package/src/plugins/ibkr/gateway/order-execution.ts +0 -218
- package/src/plugins/ibkr/gateway/orders.ts +0 -63
- package/src/plugins/ibkr/gateway/price-normalization.test.ts +0 -44
- package/src/plugins/ibkr/gateway/price-normalization.ts +0 -50
- package/src/plugins/ibkr/gateway/quote-stream-controller.ts +0 -203
- package/src/plugins/ibkr/gateway/quote-stream.ts +0 -171
- package/src/plugins/ibkr/gateway/selection.ts +0 -51
- package/src/plugins/ibkr/gateway/service/index.test.ts +0 -675
- package/src/plugins/ibkr/gateway/service/index.ts +0 -429
- package/src/plugins/ibkr/gateway/service/lifecycle.ts +0 -191
- package/src/plugins/ibkr/gateway/service/manager.ts +0 -52
- package/src/plugins/ibkr/gateway/service/market-data.ts +0 -48
- package/src/plugins/ibkr/gateway/service/native-loader.ts +0 -12
- package/src/plugins/ibkr/gateway/service/native.ts +0 -543
- package/src/plugins/ibkr/gateway/timeouts.ts +0 -13
- package/src/plugins/ibkr/gateway/types.ts +0 -27
- package/src/plugins/ibkr/index.test.tsx +0 -162
- package/src/plugins/ibkr/index.tsx +0 -159
- package/src/plugins/ibkr/instance-selection.test.ts +0 -120
- package/src/plugins/ibkr/instance-selection.ts +0 -36
- package/src/plugins/ibkr/portfolio-performance.test.ts +0 -32
- package/src/plugins/ibkr/portfolio-performance.ts +0 -129
- package/src/plugins/ibkr/trade/badge.tsx +0 -28
- package/src/plugins/ibkr/trade/dialogs.tsx +0 -44
- package/src/plugins/ibkr/trade/preview-panel.tsx +0 -130
- package/src/plugins/ibkr/trade/tab/actions.tsx +0 -443
- package/src/plugins/ibkr/trade/tab/field-editors.tsx +0 -79
- package/src/plugins/ibkr/trade/tab/footer.ts +0 -53
- package/src/plugins/ibkr/trade/tab/header.tsx +0 -167
- package/src/plugins/ibkr/trade/tab/index.test.tsx +0 -178
- package/src/plugins/ibkr/trade/tab/index.tsx +0 -298
- package/src/plugins/ibkr/trade/tab/model.ts +0 -159
- package/src/plugins/ibkr/trade/tab/order-request.ts +0 -64
- package/src/plugins/ibkr/trade/tab/shortcuts.ts +0 -89
- package/src/plugins/ibkr/trade/tab/state-sync.ts +0 -86
- package/src/plugins/ibkr/trade/ticket-panel.tsx +0 -301
- package/src/plugins/ibkr/trade/utils.test.ts +0 -175
- package/src/plugins/ibkr/trade/utils.ts +0 -144
- package/src/plugins/ibkr/trading/pane-view.tsx +0 -237
- package/src/plugins/ibkr/trading/pane.tsx +0 -332
- package/src/plugins/ibkr/trading/state.test.ts +0 -109
- package/src/plugins/ibkr/trading/state.ts +0 -335
|
@@ -81,10 +81,74 @@ function mutablePaneRegistryMap(map: ReadonlyMap<string, unknown>): Map<string,
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
describe("CommandBar", () => {
|
|
84
|
-
test("
|
|
84
|
+
test("runs symbol search for plain text and folds the hits under the local matches", async () => {
|
|
85
85
|
const searchQueries: string[] = [];
|
|
86
86
|
testSetup = await testRender(<CommandBarHarness
|
|
87
|
-
query="
|
|
87
|
+
query="msf"
|
|
88
|
+
dataProvider={makeDataProvider(async (query) => {
|
|
89
|
+
searchQueries.push(query);
|
|
90
|
+
return [
|
|
91
|
+
{ providerId: "yahoo", symbol: "MSFT", name: "Microsoft Corp", exchange: "NASDAQ", type: "EQUITY" },
|
|
92
|
+
{ providerId: "yahoo", symbol: "MSF", name: "MFS Municipal Fund", exchange: "NYSE", type: "ETF" },
|
|
93
|
+
];
|
|
94
|
+
})}
|
|
95
|
+
/>, {
|
|
96
|
+
width: 80,
|
|
97
|
+
height: 24,
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
await testSetup.renderOnce();
|
|
101
|
+
const frame = await waitForFrameToContain("Instruments");
|
|
102
|
+
expect(searchQueries.length).toBeGreaterThan(0);
|
|
103
|
+
// The listing split of the DES route is collapsed into one section, with
|
|
104
|
+
// one row per symbol, and a symbol the query spells out is promoted.
|
|
105
|
+
expect(frame).not.toContain("Other Listings");
|
|
106
|
+
// Rows lead with a class badge, so the symbol is the second token, not the line start.
|
|
107
|
+
expect(frame.split("\n").filter((line) => /^\s*\S+\s+MSFT\b/.test(line))).toHaveLength(1);
|
|
108
|
+
expect(frame).toContain("Exact Match");
|
|
109
|
+
expect(frame.indexOf("Exact Match")).toBeLessThan(frame.indexOf("Instruments"));
|
|
110
|
+
// Signed out, the AI section is a sign-up offer, which sits under the answers.
|
|
111
|
+
expect(frame.indexOf("Instruments")).toBeLessThan(frame.indexOf("Ask AI"));
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test("keeps the row the user picked when an exact symbol lands above it", async () => {
|
|
115
|
+
const created: Array<{ templateId: string; options?: PaneTemplateCreateOptions }> = [];
|
|
116
|
+
let releaseSearch = () => {};
|
|
117
|
+
const held = new Promise<void>((resolve) => { releaseSearch = resolve; });
|
|
118
|
+
testSetup = await testRender(<CommandBarHarness
|
|
119
|
+
query="list"
|
|
120
|
+
configurePluginRegistry={(pluginRegistry) => {
|
|
121
|
+
pluginRegistry.createPaneFromTemplateAsyncFn = async (templateId, options) => {
|
|
122
|
+
created.push({ templateId, options });
|
|
123
|
+
};
|
|
124
|
+
}}
|
|
125
|
+
dataProvider={makeDataProvider(async () => {
|
|
126
|
+
await held;
|
|
127
|
+
return [{ providerId: "yahoo", symbol: "LIST", name: "List Corp", exchange: "NYSE", type: "EQUITY" }];
|
|
128
|
+
})}
|
|
129
|
+
/>, {
|
|
130
|
+
width: 100,
|
|
131
|
+
height: 20,
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
await testSetup.renderOnce();
|
|
135
|
+
const before = testSetup.captureCharFrame();
|
|
136
|
+
expect(before).not.toContain("Exact Match");
|
|
137
|
+
// Down moves off the first pane match onto the second one.
|
|
138
|
+
await emitKeypress(testSetup, { name: "down" });
|
|
139
|
+
releaseSearch();
|
|
140
|
+
await waitForFrameToContain("Exact Match");
|
|
141
|
+
|
|
142
|
+
// The symbol row renumbered everything under it; Enter still runs the
|
|
143
|
+
// pane the user had picked, not whatever now sits at its old index.
|
|
144
|
+
await emitKeypress(testSetup, { name: "return", sequence: "\r" });
|
|
145
|
+
expect(created).toEqual([{ templateId: "new-watchlist-pane", options: undefined }]);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
test("keeps symbol search out of a query a prefix claims", async () => {
|
|
149
|
+
const searchQueries: string[] = [];
|
|
150
|
+
testSetup = await testRender(<CommandBarHarness
|
|
151
|
+
query="PF"
|
|
88
152
|
dataProvider={makeDataProvider(async (query) => {
|
|
89
153
|
searchQueries.push(query);
|
|
90
154
|
return [];
|
|
@@ -98,9 +162,7 @@ describe("CommandBar", () => {
|
|
|
98
162
|
await Bun.sleep(260);
|
|
99
163
|
await testSetup.renderOnce();
|
|
100
164
|
|
|
101
|
-
|
|
102
|
-
expect(frame).not.toContain("Tickers");
|
|
103
|
-
expect(frame).not.toContain("Microsoft Corp.");
|
|
165
|
+
expect(testSetup.captureCharFrame()).toContain("Shortcut: Portfolio");
|
|
104
166
|
expect(searchQueries).toEqual([]);
|
|
105
167
|
});
|
|
106
168
|
|
|
@@ -120,7 +182,7 @@ describe("CommandBar", () => {
|
|
|
120
182
|
await testSetup.renderOnce();
|
|
121
183
|
|
|
122
184
|
expect(calls).toHaveLength(1);
|
|
123
|
-
expect(testSetup.captureCharFrame()).
|
|
185
|
+
expect(testSetup.captureCharFrame()).toContain("Search or run a command");
|
|
124
186
|
});
|
|
125
187
|
|
|
126
188
|
test("shows one account management result when searching profile", async () => {
|
|
@@ -269,52 +331,6 @@ describe("CommandBar", () => {
|
|
|
269
331
|
expect(frame).toContain("SA");
|
|
270
332
|
});
|
|
271
333
|
|
|
272
|
-
test("treats plugin route trigger words as an empty plugin filter", async () => {
|
|
273
|
-
testSetup = await testRender(<CommandBarHarness query="PL plugins" />, {
|
|
274
|
-
width: 80,
|
|
275
|
-
height: 18,
|
|
276
|
-
});
|
|
277
|
-
|
|
278
|
-
await testSetup.renderOnce();
|
|
279
|
-
|
|
280
|
-
const frame = testSetup.captureCharFrame();
|
|
281
|
-
expect(frame).toContain("News");
|
|
282
|
-
expect(frame).toContain("Notes");
|
|
283
|
-
expect(frame).not.toContain("No plugins match");
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
test("finds grouped plugins through their owned feature terms", async () => {
|
|
287
|
-
testSetup = await testRender(<CommandBarHarness
|
|
288
|
-
query="PL kelly"
|
|
289
|
-
configurePluginRegistry={(pluginRegistry) => {
|
|
290
|
-
(pluginRegistry.allPlugins as Map<string, any>).set("portfolio", {
|
|
291
|
-
id: "portfolio",
|
|
292
|
-
name: "Portfolio",
|
|
293
|
-
version: "1.0.0",
|
|
294
|
-
description: "Portfolio management",
|
|
295
|
-
toggleable: true,
|
|
296
|
-
});
|
|
297
|
-
(pluginRegistry.panes as Map<string, any>).set("kelly-sizer", {
|
|
298
|
-
id: "kelly-sizer",
|
|
299
|
-
name: "Position Sizer",
|
|
300
|
-
component: () => null,
|
|
301
|
-
defaultPosition: "right",
|
|
302
|
-
});
|
|
303
|
-
const getPluginPaneIds = pluginRegistry.getPluginPaneIds;
|
|
304
|
-
pluginRegistry.getPluginPaneIds = (pluginId: string) => (
|
|
305
|
-
pluginId === "portfolio" ? ["kelly-sizer"] : getPluginPaneIds(pluginId)
|
|
306
|
-
);
|
|
307
|
-
}}
|
|
308
|
-
/>, {
|
|
309
|
-
width: 80,
|
|
310
|
-
height: 18,
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
await testSetup.renderOnce();
|
|
314
|
-
|
|
315
|
-
expect(testSetup.captureCharFrame()).toContain("Portfolio");
|
|
316
|
-
});
|
|
317
|
-
|
|
318
334
|
test("opens plugin command shortcut arguments in the wizard for confirmation", async () => {
|
|
319
335
|
const calls: Array<Record<string, string> | undefined> = [];
|
|
320
336
|
|
|
@@ -543,7 +559,9 @@ describe("CommandBar", () => {
|
|
|
543
559
|
const frame = await waitForFrameToContain("Security Description");
|
|
544
560
|
expectSingleBackControl(frame);
|
|
545
561
|
expect(frame).toContain("BRK.B");
|
|
546
|
-
|
|
562
|
+
// The class moved into the left badge; the trailing text carries only the venue.
|
|
563
|
+
expect(frame).toMatch(/EQ\s+BRK\.B.*NYSE/);
|
|
564
|
+
expect(frame).not.toContain("Equity NYSE");
|
|
547
565
|
});
|
|
548
566
|
|
|
549
567
|
test("opens ticker search when activating the Ticker Research pane item without a ticker", async () => {
|
|
@@ -557,7 +575,8 @@ describe("CommandBar", () => {
|
|
|
557
575
|
const tickerResearchRow = rootFrame
|
|
558
576
|
.split("\n")
|
|
559
577
|
.find((line) => line.includes("Ticker Research"));
|
|
560
|
-
|
|
578
|
+
// The shortcut sits in the badge column left of the label, not on the right.
|
|
579
|
+
expect(tickerResearchRow).toMatch(/^\s*T\s+Ticker Research\s*$/);
|
|
561
580
|
|
|
562
581
|
await act(async () => {
|
|
563
582
|
testSetup!.mockInput.pressEnter();
|
|
@@ -579,7 +598,6 @@ describe("CommandBar", () => {
|
|
|
579
598
|
await testSetup.renderOnce();
|
|
580
599
|
|
|
581
600
|
let frame = testSetup.captureCharFrame();
|
|
582
|
-
expect(frame).toContain("Commands");
|
|
583
601
|
expect(frame).toContain("DES");
|
|
584
602
|
expect(frame).toContain("Type a ticker symbol");
|
|
585
603
|
expect(frame).not.toContain("Back");
|
|
@@ -753,14 +771,10 @@ describe("CommandBar", () => {
|
|
|
753
771
|
await testSetup.renderOnce();
|
|
754
772
|
expect(testSetup.captureCharFrame()).toContain("DES AMD");
|
|
755
773
|
|
|
756
|
-
await
|
|
757
|
-
testSetup!.mockInput.pressKey("backspace", { meta: true });
|
|
758
|
-
await testSetup!.renderOnce();
|
|
759
|
-
});
|
|
774
|
+
await emitKeypress(testSetup, { name: "backspace", meta: true });
|
|
760
775
|
|
|
761
776
|
const frame = testSetup.captureCharFrame();
|
|
762
|
-
expect(frame).toContain("
|
|
763
|
-
expect(frame).toContain("Search");
|
|
777
|
+
expect(frame).toContain("Type a ticker symbol");
|
|
764
778
|
expect(frame).not.toContain("DES AMD");
|
|
765
779
|
});
|
|
766
780
|
|
|
@@ -777,7 +791,7 @@ describe("CommandBar", () => {
|
|
|
777
791
|
await testSetup!.renderOnce();
|
|
778
792
|
});
|
|
779
793
|
|
|
780
|
-
expect(testSetup.captureCharFrame()).
|
|
794
|
+
expect(testSetup.captureCharFrame()).toContain("Search or run a command");
|
|
781
795
|
});
|
|
782
796
|
|
|
783
797
|
test("DES MSFT opens an exact ticker directly", async () => {
|
|
@@ -886,13 +900,15 @@ describe("CommandBar", () => {
|
|
|
886
900
|
|
|
887
901
|
await testSetup.renderOnce();
|
|
888
902
|
|
|
903
|
+
// Below the sheet; the header row above it hosts the input and is not
|
|
904
|
+
// click-away territory.
|
|
889
905
|
await act(async () => {
|
|
890
|
-
await testSetup!.mockMouse.click(0,
|
|
906
|
+
await testSetup!.mockMouse.click(0, 22);
|
|
891
907
|
await testSetup!.renderOnce();
|
|
892
908
|
});
|
|
893
909
|
await testSetup.renderOnce();
|
|
894
910
|
|
|
895
|
-
expect(testSetup.captureCharFrame()).
|
|
911
|
+
expect(testSetup.captureCharFrame()).toContain("Search or run a command");
|
|
896
912
|
});
|
|
897
913
|
|
|
898
914
|
test("groups ticker search sections and keeps saved matches above looser provider results", async () => {
|
|
@@ -917,8 +933,8 @@ describe("CommandBar", () => {
|
|
|
917
933
|
const rows = frame.split("\n");
|
|
918
934
|
const savedHeadings = frame.split("\n").filter((line) => line.trim() === "Saved");
|
|
919
935
|
const otherListingsHeadings = frame.split("\n").filter((line) => line.trim() === "Other Listings");
|
|
920
|
-
const aaplRow = rows.findIndex((line) => line
|
|
921
|
-
const appRow = rows.findIndex((line) => line
|
|
936
|
+
const aaplRow = rows.findIndex((line) => /^\s*\S+\s+AAPL\b/.test(line));
|
|
937
|
+
const appRow = rows.findIndex((line) => /^\s*\S+\s+APP\b/.test(line));
|
|
922
938
|
expect(savedHeadings).toHaveLength(1);
|
|
923
939
|
expect(otherListingsHeadings).toHaveLength(1);
|
|
924
940
|
expect(aaplRow).toBeGreaterThanOrEqual(0);
|
|
@@ -983,8 +999,8 @@ describe("CommandBar", () => {
|
|
|
983
999
|
await testSetup.renderOnce();
|
|
984
1000
|
const frame = await waitForFrameToContain("APLY");
|
|
985
1001
|
const rows = frame.split("\n");
|
|
986
|
-
const aaplRow = rows.findIndex((line) => line
|
|
987
|
-
const apcRow = rows.findIndex((line) => line
|
|
1002
|
+
const aaplRow = rows.findIndex((line) => /^\s*\S+\s+AAPL\b/.test(line));
|
|
1003
|
+
const apcRow = rows.findIndex((line) => /^\s*\S+\s+APC\b/.test(line));
|
|
988
1004
|
|
|
989
1005
|
expect(aaplRow).toBeGreaterThanOrEqual(0);
|
|
990
1006
|
expect(apcRow).toBeGreaterThanOrEqual(0);
|
|
@@ -7,13 +7,10 @@ import { usePlanAccess } from "../../../plugins/builtin/shared/plan-access";
|
|
|
7
7
|
import { buildAssistCommandInventory } from "../assist/inventory";
|
|
8
8
|
import { useCommandBarAssist } from "../assist/runtime";
|
|
9
9
|
import { shouldAutoAskAssist, type AssistRowHandlers } from "../assist/model";
|
|
10
|
-
import { useNewsArticles } from "../../../news/hooks";
|
|
11
10
|
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
} from "../../../plugins/builtin/news/wire/article-search";
|
|
16
|
-
import { buildArticleSearchResultItems } from "../routes/root/article-results";
|
|
11
|
+
getAvailableCommandBarSearchProviders,
|
|
12
|
+
useCommandBarSearchProviders,
|
|
13
|
+
} from "../routes/root/search-providers";
|
|
17
14
|
import { openUrl } from "../../ui/external-link";
|
|
18
15
|
import { useRouteListState } from "../routing/list-state";
|
|
19
16
|
import { useCommandBarRootRuntime } from "../routes/root/runtime";
|
|
@@ -57,6 +54,7 @@ export function CommandBar({
|
|
|
57
54
|
getCommittedThemeId,
|
|
58
55
|
nativeListScrollRef,
|
|
59
56
|
nativePaneChrome,
|
|
57
|
+
nativeWindowChrome,
|
|
60
58
|
persistConfig,
|
|
61
59
|
skipTickerSearchDebounceRef,
|
|
62
60
|
state,
|
|
@@ -113,7 +111,6 @@ export function CommandBar({
|
|
|
113
111
|
adaptTickerSearchRouteResult,
|
|
114
112
|
buildLayoutItems,
|
|
115
113
|
buildPaneSettingItems,
|
|
116
|
-
buildPluginItems,
|
|
117
114
|
buildTickerSearchResultItems,
|
|
118
115
|
buildWindowModeItems,
|
|
119
116
|
collectionWorkflowActions,
|
|
@@ -258,31 +255,30 @@ export function CommandBar({
|
|
|
258
255
|
),
|
|
259
256
|
}), [askAssistNow, assistActive, assistAutoAsk, assistState, planAccess.emailVerified, startAssistSignUp]);
|
|
260
257
|
|
|
261
|
-
const
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
}, [closeAll, newsState.articles, newsState.phase, rootQuery]);
|
|
258
|
+
const searchProviders = useMemo(
|
|
259
|
+
() => getAvailableCommandBarSearchProviders(pluginRegistry, state.config.disabledPlugins),
|
|
260
|
+
[pluginRegistry, state.config.disabledPlugins],
|
|
261
|
+
);
|
|
262
|
+
const searchProviderContext = useMemo(() => ({
|
|
263
|
+
activeTicker: activeTickerSymbol,
|
|
264
|
+
activeCollectionId,
|
|
265
|
+
}), [activeCollectionId, activeTickerSymbol]);
|
|
266
|
+
const closeAfterProviderResult = useCallback(() => {
|
|
267
|
+
closeAll({ revertThemePreview: false });
|
|
268
|
+
}, [closeAll]);
|
|
269
|
+
const { providerResultItems, providerSearching } = useCommandBarSearchProviders({
|
|
270
|
+
providers: searchProviders,
|
|
271
|
+
query: rootQuery,
|
|
272
|
+
// A resolved prefix means the user is running a command, so free-text
|
|
273
|
+
// providers neither ask the network nor add rows.
|
|
274
|
+
enabled: !currentRoute && rootShortcutIntent.kind === "none",
|
|
275
|
+
context: searchProviderContext,
|
|
276
|
+
onExecuted: closeAfterProviderResult,
|
|
277
|
+
});
|
|
278
|
+
const providerCategoryPriorities = useMemo(
|
|
279
|
+
() => new Map(searchProviders.map((provider) => [provider.category, provider.priority ?? 0])),
|
|
280
|
+
[searchProviders],
|
|
281
|
+
);
|
|
286
282
|
|
|
287
283
|
const {
|
|
288
284
|
activeMatch,
|
|
@@ -302,7 +298,6 @@ export function CommandBar({
|
|
|
302
298
|
availableCommands,
|
|
303
299
|
buildLayoutItems,
|
|
304
300
|
buildPaneSettingItems,
|
|
305
|
-
buildPluginItems,
|
|
306
301
|
buildTickerSearchResultItems,
|
|
307
302
|
buildWindowModeItems,
|
|
308
303
|
createPaneTemplateItem,
|
|
@@ -320,7 +315,9 @@ export function CommandBar({
|
|
|
320
315
|
paneShortcutItems,
|
|
321
316
|
pluginCommandItems,
|
|
322
317
|
pluginCommandResultItems,
|
|
323
|
-
|
|
318
|
+
providerResultItems,
|
|
319
|
+
providerCategoryPriorities,
|
|
320
|
+
providerSearching,
|
|
324
321
|
readTickerSearchCache,
|
|
325
322
|
rootModeKind: rootModeInfo.kind,
|
|
326
323
|
rootQuery,
|
|
@@ -384,10 +381,10 @@ export function CommandBar({
|
|
|
384
381
|
adaptTickerSearchRouteResult,
|
|
385
382
|
buildLayoutItems,
|
|
386
383
|
buildPaneSettingItems,
|
|
387
|
-
buildPluginItems,
|
|
388
384
|
currentRoute,
|
|
389
385
|
orderedRootResults,
|
|
390
386
|
pluginRegistry,
|
|
387
|
+
rootCategoryPriorities: providerCategoryPriorities,
|
|
391
388
|
rootHoveredIdx,
|
|
392
389
|
rootModeKind: rootModeInfo.kind,
|
|
393
390
|
rootQuery,
|
|
@@ -432,6 +429,7 @@ export function CommandBar({
|
|
|
432
429
|
moveWorkflowFocus,
|
|
433
430
|
nativeListScrollRef,
|
|
434
431
|
nativePaneChrome,
|
|
432
|
+
nativeWindowChrome,
|
|
435
433
|
onNativeOccluderChange,
|
|
436
434
|
openWorkflowFieldPicker,
|
|
437
435
|
persistConfig,
|
|
@@ -440,7 +438,6 @@ export function CommandBar({
|
|
|
440
438
|
resetAssist,
|
|
441
439
|
rootModeKind: rootModeInfo.kind,
|
|
442
440
|
rootGhostSuffix,
|
|
443
|
-
rootQueryLength: rootQuery.length,
|
|
444
441
|
rootShortcutFeedback,
|
|
445
442
|
routeListState,
|
|
446
443
|
setActiveListQuery,
|
|
@@ -18,7 +18,8 @@ import type { TickerRecord } from "../../../types/ticker";
|
|
|
18
18
|
import type { PluginRegistry } from "../../../plugins/registry";
|
|
19
19
|
import type { PaneSettingField } from "../../../types/plugin";
|
|
20
20
|
import { useShortcut } from "../../../react/input";
|
|
21
|
-
import { Text } from "../../../ui";
|
|
21
|
+
import { Box, Text } from "../../../ui";
|
|
22
|
+
import { Header } from "../../layout/header";
|
|
22
23
|
|
|
23
24
|
export async function emitKeypress(
|
|
24
25
|
renderer: Awaited<ReturnType<typeof testRender>>,
|
|
@@ -213,6 +214,8 @@ function makePluginRegistry(hasPaneSettings: (paneId: string) => boolean = () =>
|
|
|
213
214
|
execute: async () => {},
|
|
214
215
|
}],
|
|
215
216
|
]),
|
|
217
|
+
commandBarSearchProviders: new Map<string, any>(),
|
|
218
|
+
getCommandBarSearchProviderPluginId: () => undefined,
|
|
216
219
|
tickerActions: new Map<string, any>([
|
|
217
220
|
["pin", {
|
|
218
221
|
id: "pin",
|
|
@@ -385,8 +388,17 @@ export function CommandBarHarness({
|
|
|
385
388
|
<ThemeProvider themeId={getEffectiveThemeId(currentState)}>
|
|
386
389
|
<AppContext value={{ state: currentState, dispatch: currentDispatch }}>
|
|
387
390
|
<TestDialogProvider>
|
|
388
|
-
{
|
|
389
|
-
|
|
391
|
+
{/* The header hosts the bar's input while it is open, so typing in a
|
|
392
|
+
test needs the real header on the first row. */}
|
|
393
|
+
<Header />
|
|
394
|
+
<Box flexGrow={1} />
|
|
395
|
+
{/* The sheet spans the full width and can reach as far down as
|
|
396
|
+
termHeight - 6 (panel/layout.ts), so probes live on the bottom row,
|
|
397
|
+
the one place no sheet height can cover. */}
|
|
398
|
+
<Box flexDirection="row" gap={1} height={1}>
|
|
399
|
+
{live && <ThemeProbe />}
|
|
400
|
+
{showQueryState && <Text>{`query:${currentState.commandBarQuery}`}</Text>}
|
|
401
|
+
</Box>
|
|
390
402
|
{currentState.commandBarOpen && (
|
|
391
403
|
<CommandBar
|
|
392
404
|
dataProvider={dataProvider}
|
|
@@ -13,14 +13,42 @@ import { Box, Text } from "../../ui";
|
|
|
13
13
|
import { TextAttributes } from "../../ui";
|
|
14
14
|
import { ListView, type ListViewItem } from "../ui";
|
|
15
15
|
import type { ListRowState } from "../ui/list-view";
|
|
16
|
-
import { getThemeIds, themes as themeRegistry } from "../../theme/themes";
|
|
16
|
+
import { getThemeIds, isDarkTheme, themes as themeRegistry } from "../../theme/themes";
|
|
17
17
|
import { truncateText } from "./view-model";
|
|
18
18
|
|
|
19
19
|
const THEME_PREVIEW_DEBOUNCE_MS = 120;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Marks the dark half of the list. The registry's own order groups themes by
|
|
22
|
+
* family, which only helps if you already know which family you want; sorted by
|
|
23
|
+
* name you can find one by reading, and the glyph carries the grouping the
|
|
24
|
+
* order used to.
|
|
25
|
+
*/
|
|
26
|
+
const DARK_THEME_GLYPH = "☾";
|
|
27
|
+
/** The glyph plus the space that keeps names on one left edge, dark or light. */
|
|
28
|
+
const GLYPH_GUTTER_WIDTH = 2;
|
|
29
|
+
|
|
30
|
+
export interface ThemeOption {
|
|
31
|
+
id: string;
|
|
32
|
+
name: string;
|
|
33
|
+
dark: boolean;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const THEME_OPTIONS: ThemeOption[] = getThemeIds()
|
|
37
|
+
.map((id) => ({ id, name: themeRegistry[id]!.name, dark: isDarkTheme(id) }))
|
|
38
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Shared with the panel layout, which sizes the sheet to whatever this returns
|
|
42
|
+
* so the picker never opens taller than the themes it can show.
|
|
43
|
+
*/
|
|
44
|
+
export function matchThemeOptions(filter: string): ThemeOption[] {
|
|
45
|
+
const normalized = filter.trim().toLowerCase();
|
|
46
|
+
if (!normalized) return THEME_OPTIONS;
|
|
47
|
+
return THEME_OPTIONS.filter((theme) => (
|
|
48
|
+
theme.name.toLowerCase().includes(normalized)
|
|
49
|
+
|| theme.id.toLowerCase().includes(normalized)
|
|
50
|
+
));
|
|
51
|
+
}
|
|
24
52
|
|
|
25
53
|
interface ThemePickerScrollEvent {
|
|
26
54
|
stopPropagation: () => void;
|
|
@@ -83,13 +111,7 @@ export const ThemePicker = memo(forwardRef<ThemePickerHandle, ThemePickerProps>(
|
|
|
83
111
|
const onPreviewRef = useRef(onPreview);
|
|
84
112
|
const onCommitRef = useRef(onCommit);
|
|
85
113
|
const normalizedFilter = filter.trim().toLowerCase();
|
|
86
|
-
const themes = useMemo(() =>
|
|
87
|
-
if (!normalizedFilter) return THEME_OPTIONS;
|
|
88
|
-
return THEME_OPTIONS.filter((theme) => (
|
|
89
|
-
theme.name.toLowerCase().includes(normalizedFilter)
|
|
90
|
-
|| theme.id.toLowerCase().includes(normalizedFilter)
|
|
91
|
-
));
|
|
92
|
-
}, [normalizedFilter]);
|
|
114
|
+
const themes = useMemo(() => matchThemeOptions(normalizedFilter), [normalizedFilter]);
|
|
93
115
|
const [selectedIndex, setSelectedIndex] = useState(() => (
|
|
94
116
|
Math.max(0, themes.findIndex((theme) => theme.id === committedThemeId))
|
|
95
117
|
));
|
|
@@ -199,8 +221,9 @@ export const ThemePicker = memo(forwardRef<ThemePickerHandle, ThemePickerProps>(
|
|
|
199
221
|
onCommitRef.current(selected.id);
|
|
200
222
|
}, [cancelPreview]);
|
|
201
223
|
|
|
224
|
+
const nameWidth = Math.max(1, labelWidth - GLYPH_GUTTER_WIDTH);
|
|
202
225
|
const renderRow = useCallback((item: ListViewItem, state: ListRowState) => {
|
|
203
|
-
const label = truncateText(item.label,
|
|
226
|
+
const label = truncateText(item.label, nameWidth);
|
|
204
227
|
const trailing = item.current ? "current" : "";
|
|
205
228
|
return (
|
|
206
229
|
<Box
|
|
@@ -211,7 +234,12 @@ export const ThemePicker = memo(forwardRef<ThemePickerHandle, ThemePickerProps>(
|
|
|
211
234
|
data-command-bar-row-selected={nativePaneChrome && state.selected ? "true" : undefined}
|
|
212
235
|
style={nativePaneChrome ? { borderRadius: 6 } : undefined}
|
|
213
236
|
>
|
|
214
|
-
<Box width={
|
|
237
|
+
<Box width={GLYPH_GUTTER_WIDTH}>
|
|
238
|
+
<Text fg={state.selected ? paletteSelectedText : paletteSubtleText}>
|
|
239
|
+
{isDarkTheme(item.id) ? DARK_THEME_GLYPH : ""}
|
|
240
|
+
</Text>
|
|
241
|
+
</Box>
|
|
242
|
+
<Box width={nameWidth}>
|
|
215
243
|
<Text
|
|
216
244
|
fg={state.selected ? paletteSelectedText : paletteText}
|
|
217
245
|
attributes={item.current ? TextAttributes.BOLD : undefined}
|
|
@@ -228,7 +256,7 @@ export const ThemePicker = memo(forwardRef<ThemePickerHandle, ThemePickerProps>(
|
|
|
228
256
|
);
|
|
229
257
|
}, [
|
|
230
258
|
contentPadding,
|
|
231
|
-
|
|
259
|
+
nameWidth,
|
|
232
260
|
nativePaneChrome,
|
|
233
261
|
paletteSelectedText,
|
|
234
262
|
paletteSubtleText,
|
|
@@ -13,7 +13,6 @@ describe("command bar view model helpers", () => {
|
|
|
13
13
|
expect(resolveCommandBarMode("DES NVDA")).toMatchObject({ kind: "search", badge: "DES" });
|
|
14
14
|
expect(resolveCommandBarMode("T NVDA")).toMatchObject({ kind: "search", badge: "T" });
|
|
15
15
|
expect(resolveCommandBarMode("TH ")).toMatchObject({ kind: "themes", badge: "THEMES" });
|
|
16
|
-
expect(resolveCommandBarMode("PL notes")).toMatchObject({ kind: "plugins", badge: "PLUGINS" });
|
|
17
16
|
expect(resolveCommandBarMode("LAY")).toMatchObject({ kind: "direct-command", badge: "COMMAND" });
|
|
18
17
|
expect(resolveCommandBarMode("LMA ")).toMatchObject({ kind: "layout", badge: "LAYOUT" });
|
|
19
18
|
expect(resolveCommandBarMode("NP ")).toMatchObject({ kind: "default", badge: "FILTER" });
|
|
@@ -48,23 +47,69 @@ describe("command bar view model helpers", () => {
|
|
|
48
47
|
expect(sections.map((section) => section.category)).toEqual(["Tickers", "Config", "Danger", "Debug"]);
|
|
49
48
|
});
|
|
50
49
|
|
|
51
|
-
test("drops an offer-only section below real matches
|
|
50
|
+
test("drops an offer-only section below real matches whatever its category priority", () => {
|
|
52
51
|
const sections = buildSections([
|
|
53
|
-
{ id: "
|
|
52
|
+
{ id: "exact", category: "Exact Match", disabled: true, defaultSelectable: false },
|
|
54
53
|
{ id: "holders", category: "Panes" },
|
|
55
54
|
]);
|
|
56
55
|
|
|
57
|
-
expect(sections.map((section) => section.category)).toEqual(["Panes", "
|
|
56
|
+
expect(sections.map((section) => section.category)).toEqual(["Panes", "Exact Match"]);
|
|
58
57
|
expect(sections[0]?.items[0]?.id).toBe("holders");
|
|
59
58
|
});
|
|
60
59
|
|
|
61
|
-
test("
|
|
62
|
-
|
|
60
|
+
test("leads with an exact symbol, then the AI, then the async sections in arrival order", () => {
|
|
61
|
+
// An exactly matching symbol is the most certain answer available, so it
|
|
62
|
+
// outranks the AI's reading of the same query. Below it the AI leads even
|
|
63
|
+
// though it answers last, since it turns the typed sentence into commands;
|
|
64
|
+
// its placeholder holds the rows meanwhile. Symbol search and documents
|
|
65
|
+
// arrive in that order under the local matches, so each only pushes rows
|
|
66
|
+
// below itself. Documents come from a provider, which contributes its own
|
|
67
|
+
// priority.
|
|
68
|
+
const items = [
|
|
69
|
+
{ id: "doc", category: "Documents" },
|
|
70
|
+
{ id: "nvda-mx", category: "Instruments" },
|
|
71
|
+
{ id: "nvda", category: "Exact Match" },
|
|
72
|
+
{ id: "holders", category: "Panes" },
|
|
73
|
+
{ id: "help", category: "Commands" },
|
|
74
|
+
{ id: "quit", category: "Application" },
|
|
75
|
+
{ id: "plugin-row", category: "Portfolio" },
|
|
63
76
|
{ id: "assist:candidate:0", category: "Ask AI" },
|
|
77
|
+
];
|
|
78
|
+
const categoryPriorities = new Map([["Documents", 200]]);
|
|
79
|
+
|
|
80
|
+
for (const sectionOrder of ["default", "app-first"] as const) {
|
|
81
|
+
const sections = buildSections(items, { sectionOrder, categoryPriorities });
|
|
82
|
+
expect(sections.map((section) => section.category)).toEqual([
|
|
83
|
+
"Exact Match",
|
|
84
|
+
"Ask AI",
|
|
85
|
+
"Panes",
|
|
86
|
+
"Commands",
|
|
87
|
+
"Application",
|
|
88
|
+
"Portfolio",
|
|
89
|
+
"Instruments",
|
|
90
|
+
"Documents",
|
|
91
|
+
]);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test("drops the AI's sign-up offer under the async sections", () => {
|
|
96
|
+
const sections = buildSections([
|
|
97
|
+
{ id: "assist:sign-up", category: "Ask AI", defaultSelectable: false },
|
|
98
|
+
{ id: "doc", category: "Documents" },
|
|
99
|
+
{ id: "nvda-mx", category: "Instruments" },
|
|
64
100
|
{ id: "holders", category: "Panes" },
|
|
65
|
-
]);
|
|
101
|
+
], { categoryPriorities: new Map([["Documents", 200]]) });
|
|
102
|
+
|
|
103
|
+
expect(sections.map((section) => section.category)).toEqual(["Panes", "Instruments", "Documents", "Ask AI"]);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test("lets a provider's contributed priority override the built-in band", () => {
|
|
107
|
+
const sections = buildSections([
|
|
108
|
+
{ id: "nvda-mx", category: "Instruments" },
|
|
109
|
+
{ id: "doc", category: "Documents" },
|
|
110
|
+
], { categoryPriorities: new Map([["Documents", -200]]) });
|
|
66
111
|
|
|
67
|
-
expect(sections.map((section) => section.category)).toEqual(["
|
|
112
|
+
expect(sections.map((section) => section.category)).toEqual(["Documents", "Instruments"]);
|
|
68
113
|
});
|
|
69
114
|
|
|
70
115
|
test("keeps non-exact ticker suggestions behind app sections in app-first order", () => {
|