gloomberb 0.10.0 → 0.10.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/package.json +8 -1
- package/src/api-client/auth.ts +1 -0
- package/src/api-client/index.test.ts +359 -108
- package/src/api-client/index.ts +24 -13
- package/src/api-client/socket.ts +70 -35
- package/src/api-client/types.ts +1 -1
- package/src/app/language-observer.test.tsx +82 -0
- package/src/app/language-observer.tsx +13 -0
- package/src/app/pane-runtime/index.tsx +2 -2
- package/src/app/pane-runtime/pane-settings-runtime.tsx +2 -2
- package/src/app/pane-runtime/pane-template-runtime.ts +2 -2
- package/src/app/pane-runtime/plugin-bindings.ts +2 -2
- package/src/app/pane-runtime/ticker-open-runtime.ts +2 -2
- package/src/app/runtime/broker-import.ts +2 -2
- package/src/app/runtime/plugin-bindings.ts +2 -2
- package/src/app/runtime/startup.ts +2 -2
- package/src/app.tsx +16 -7
- package/src/brokers/account-cache.ts +6 -6
- package/src/brokers/broker-ticker-sync.ts +3 -3
- package/src/brokers/remote-broker-adapter.ts +2 -2
- package/src/brokers/sync-broker-instance.ts +5 -6
- package/src/cli/commands/api.ts +3 -6
- package/src/cli/commands/automation.ts +7 -15
- package/src/cli/commands/market.ts +26 -61
- package/src/cli/commands/overview.ts +34 -45
- package/src/cli/commands/search.ts +25 -27
- package/src/cli/commands/system.ts +27 -57
- package/src/cli/commands/ticker.ts +62 -63
- package/src/cli/context.test.ts +63 -0
- package/src/cli/context.ts +15 -1
- package/src/cli/index.ts +1 -1
- package/src/cli/pane-functions/data.ts +2 -19
- package/src/cli/pane-functions/index.ts +26 -25
- package/src/cli/pane-functions/report.ts +1 -1
- package/src/cli/pane-functions/screenshot.ts +3 -3
- package/src/cli/scoped-context.ts +41 -0
- package/src/components/chart/composite/composite-chart.test.tsx +615 -18
- package/src/components/chart/composite/composite-chart.tsx +179 -79
- package/src/components/chart/composite/format.test.ts +20 -7
- package/src/components/chart/composite/index.ts +0 -21
- package/src/components/chart/composite/interactions.test.ts +90 -3
- package/src/components/chart/composite/interactions.ts +189 -24
- package/src/components/chart/composite/price-series.ts +0 -2
- package/src/components/chart/composite/rasterizer.ts +10 -9
- package/src/components/chart/composite/renderers.test.ts +108 -2
- package/src/components/chart/composite/scene.test.ts +36 -0
- package/src/components/chart/composite/scene.ts +5 -2
- package/src/components/chart/composite/text-renderer.ts +37 -25
- package/src/components/chart/composite/time-axis.test.ts +243 -0
- package/src/components/chart/composite/time-axis.ts +608 -0
- package/src/components/chart/composite/types.ts +12 -1
- package/src/components/chart/core/data.ts +2 -159
- package/src/components/chart/core/date-window.ts +6 -225
- package/src/components/chart/core/palette.ts +1 -12
- package/src/components/chart/core/pointer.ts +0 -142
- package/src/components/chart/core/types.ts +1 -58
- package/src/components/chart/cursor-motion.ts +2 -4
- package/src/components/chart/indicators/types.ts +0 -9
- package/src/components/chart/market-session.ts +0 -11
- package/src/components/chart/native/kitty/protocol.ts +1 -1
- package/src/components/chart/native/raster/layout.ts +3 -10
- package/src/components/chart/static/chart/axis-overlays.test.tsx +64 -0
- package/src/components/chart/static/chart/axis-overlays.tsx +59 -14
- package/src/components/chart/static/chart/surface.tsx +1 -2
- package/src/components/command-bar/action-runtime.ts +2 -2
- package/src/components/command-bar/commands/direct/index.ts +1 -1
- package/src/components/command-bar/panel/body.tsx +2 -2
- package/src/components/command-bar/panel/index.tsx +11 -9
- package/src/components/command-bar/routes/ticker-search/actions.ts +2 -2
- package/src/components/command-bar/surface/index.tsx +2 -2
- package/src/components/command-bar/workflow/body.tsx +3 -3
- package/src/components/command-bar/workflow/collection-actions.ts +2 -2
- package/src/components/command-bar/workflow/coordinator.ts +2 -2
- package/src/components/command-bar/workflow/field-row.tsx +25 -11
- package/src/components/command-bar/workflow/tickers.ts +2 -2
- package/src/components/feed-data-table/stack-view.test.tsx +28 -36
- package/src/components/feed-data-table/stack-view.tsx +3 -1
- package/src/components/layout/detached-pane-shell.tsx +6 -6
- package/src/components/layout/header.tsx +13 -9
- package/src/components/layout/pane/content.test.tsx +42 -3
- package/src/components/layout/pane/content.tsx +3 -1
- package/src/components/layout/pane/footer/index.test.tsx +45 -2
- package/src/components/layout/pane/footer/registration.tsx +3 -1
- package/src/components/layout/shell/index.tsx +1 -2
- package/src/components/layout/shell/native/surfaces.ts +1 -1
- package/src/components/layout/shell/native/window-state.ts +1 -1
- package/src/components/layout/status-bar.tsx +12 -8
- package/src/components/layout/window-controls.tsx +8 -6
- package/src/components/onboarding/onboarding-wizard.tsx +3 -1
- package/src/components/pane-settings-dialog/desktop.tsx +0 -2
- package/src/components/pane-settings-dialog.tsx +0 -2
- package/src/components/pane-template-wizard.tsx +10 -9
- package/src/components/price-performance.tsx +2 -113
- package/src/components/price-sparkline/model.ts +15 -17
- package/src/components/price-sparkline/view.tsx +8 -7
- package/src/components/speedometer-gauge/desktop.tsx +2 -1
- package/src/components/speedometer-gauge/index.tsx +0 -2
- package/src/components/speedometer-gauge/terminal.tsx +24 -5
- package/src/components/ticker/badge/index.tsx +1 -18
- package/src/components/ui/data-table/opentui/index.tsx +3 -3
- package/src/components/ui/frame.tsx +1 -2
- package/src/components/ui/page-stack-view.test.tsx +126 -0
- package/src/components/ui/page-stack-view.tsx +24 -12
- package/src/components/ui/tabs.tsx +7 -3
- package/src/components/ui/ui.test.tsx +23 -2
- package/src/components/use-external-link-footer.ts +4 -2
- package/src/core/app-service-ports.ts +46 -0
- package/src/core/app-services.test.ts +66 -0
- package/src/core/app-services.ts +17 -15
- package/src/data/config/chart-settings.ts +3 -10
- package/src/data/config/store/index.test.ts +99 -2
- package/src/data/config/store/migrations.ts +278 -0
- package/src/data/config/store/normalize.ts +44 -186
- package/src/data/resource-store.ts +73 -12
- package/src/data/sqlite/cache.test.ts +104 -15
- package/src/i18n/index.test.ts +17 -0
- package/src/i18n/index.ts +23 -6
- package/src/i18n/ja.ts +13 -0
- package/src/i18n/ko.ts +13 -0
- package/src/i18n/react.ts +6 -0
- package/src/i18n/zh-cn.ts +13 -0
- package/src/i18n/zh-tw.ts +13 -0
- package/src/market-data/coordinator/auxiliary.ts +7 -3
- package/src/market-data/coordinator/chart.ts +1 -1
- package/src/market-data/coordinator/index.test.ts +26 -0
- package/src/market-data/coordinator/index.ts +11 -5
- package/src/market-data/coordinator/quotes.ts +4 -40
- package/src/market-data/coordinator/subscriptions.test.ts +89 -1
- package/src/market-data/hooks.tsx +47 -1
- package/src/market-data/market/status.ts +6 -6
- package/src/market-data/performance.ts +1 -1
- package/src/market-data/quote-subscription-target.test.ts +37 -0
- package/src/market-data/quote-subscription-target.ts +60 -0
- package/src/market-data/quotes/freshness.ts +1 -0
- package/src/market-data/quotes/resolution.ts +4 -0
- package/src/market-data/request-types.ts +3 -3
- package/src/news/aggregator.test.ts +97 -1
- package/src/news/aggregator.ts +100 -57
- package/src/news/hooks.test.tsx +64 -0
- package/src/news/hooks.ts +18 -25
- package/src/plugins/builtin/account-management/footer.ts +4 -2
- package/src/plugins/builtin/account-management/pane.tsx +9 -4
- package/src/plugins/builtin/ai/agent-history.ts +11 -7
- package/src/plugins/builtin/ai/ask-ai-detail-tab.tsx +0 -5
- package/src/plugins/builtin/ai/ask-ai.test.tsx +3 -4
- package/src/plugins/builtin/ai/index.test.ts +2 -2
- package/src/plugins/builtin/ai/index.tsx +10 -11
- package/src/plugins/builtin/ai/pane-settings.ts +1 -1
- package/src/plugins/builtin/ai/pi/runtime.ts +6 -5
- package/src/plugins/builtin/ai/providers.ts +1 -9
- package/src/plugins/builtin/ai/runner.ts +0 -6
- package/src/plugins/builtin/ai/screener/footer.ts +4 -1
- package/src/plugins/builtin/ai/screener/pane.test.tsx +9 -9
- package/src/plugins/builtin/ai/workspace/model.ts +2 -27
- package/src/plugins/builtin/ai/workspace/pane.tsx +2 -2
- package/src/plugins/builtin/analytics/metrics.ts +1 -7
- package/src/plugins/builtin/broker-manager/detail.tsx +3 -2
- package/src/plugins/builtin/broker-manager/index.tsx +4 -2
- package/src/plugins/builtin/chart-composer/editor/controller.ts +643 -0
- package/src/plugins/builtin/chart-composer/editor/desktop-view.tsx +134 -0
- package/src/plugins/builtin/chart-composer/editor/model.test.ts +85 -0
- package/src/plugins/builtin/chart-composer/editor/model.ts +292 -0
- package/src/plugins/builtin/chart-composer/editor/opentui-view.tsx +108 -0
- package/src/plugins/builtin/chart-composer/editor.tsx +65 -947
- package/src/plugins/builtin/chart-composer/index.tsx +0 -6
- package/src/plugins/builtin/chart-composer/pane.tsx +69 -36
- package/src/plugins/builtin/chart-composer/presets.ts +1 -19
- package/src/plugins/builtin/chart-composer/settings.ts +1 -1
- package/src/plugins/builtin/chat/content/composer-runtime.ts +1 -1
- package/src/plugins/builtin/chat/content/shortcuts.ts +0 -1
- package/src/plugins/builtin/chat/controller/fetch.ts +8 -2
- package/src/plugins/builtin/chat/controller/persistence.ts +2 -0
- package/src/plugins/builtin/chat/controller/session.test.ts +25 -0
- package/src/plugins/builtin/chat/controller/session.ts +2 -0
- package/src/plugins/builtin/chat/controller/state.ts +7 -0
- package/src/plugins/builtin/chat/controller.test.ts +73 -20
- package/src/plugins/builtin/chat/message/desktop.tsx +2 -0
- package/src/plugins/builtin/cloud-tweets/footer.ts +9 -28
- package/src/plugins/builtin/cloud-tweets/pane.tsx +0 -5
- package/src/plugins/builtin/cloud-tweets/table.tsx +12 -17
- package/src/plugins/builtin/correlation/compute.ts +4 -10
- package/src/plugins/builtin/econ/index.tsx +17 -19
- package/src/plugins/builtin/holders/types.ts +0 -1
- package/src/plugins/builtin/insider/index.tsx +6 -31
- package/src/plugins/builtin/news/index.tsx +5 -7
- package/src/plugins/builtin/news/wire/breaking/pane.test.tsx +6 -8
- package/src/plugins/builtin/news/wire/news/footer.ts +10 -11
- package/src/plugins/builtin/news/wire/read-state.test.ts +7 -0
- package/src/plugins/builtin/news/wire/read-state.ts +18 -28
- package/src/plugins/builtin/news/wire/rss/parser.ts +1 -11
- package/src/plugins/builtin/options/footer.test.ts +115 -0
- package/src/plugins/builtin/options/footer.ts +110 -0
- package/src/plugins/builtin/options/live-quotes.test.ts +238 -0
- package/src/plugins/builtin/options/live-quotes.ts +147 -0
- package/src/plugins/builtin/options/view.test.tsx +71 -1
- package/src/plugins/builtin/options/view.tsx +39 -24
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +103 -117
- package/src/plugins/builtin/portfolio-list/cli/render.ts +11 -5
- package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +120 -135
- package/src/plugins/builtin/portfolio-list/header.tsx +9 -4
- package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +6 -1
- package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +4 -2
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +24 -52
- package/src/plugins/builtin/sec/filing-content.test.ts +41 -0
- package/src/plugins/builtin/sec/filing-content.ts +94 -0
- package/src/plugins/builtin/sec/index.tsx +21 -104
- package/src/plugins/builtin/sectors/sector-model.ts +1 -7
- package/src/plugins/builtin/shared/cloud-upgrade.ts +1 -0
- package/src/plugins/builtin/shared/pane-footer.ts +82 -0
- package/src/plugins/builtin/shared/read-state.ts +64 -3
- package/src/plugins/builtin/substack/read-state.ts +16 -41
- package/src/plugins/builtin/thirteenf/pane.tsx +24 -73
- package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +10 -10
- package/src/plugins/builtin/yield-curve/index.tsx +11 -9
- package/src/plugins/ibkr/dialogs.tsx +3 -3
- package/src/plugins/ibkr/gateway/fundamentals.ts +1 -1
- package/src/plugins/ibkr/gateway/history-requests.ts +2 -2
- package/src/plugins/ibkr/gateway/history.ts +2 -2
- package/src/plugins/ibkr/gateway/selection.ts +2 -2
- package/src/plugins/ibkr/gateway/service/index.ts +2 -2
- package/src/plugins/ibkr/gateway/service/native.ts +2 -2
- package/src/plugins/plugin-persistence.ts +3 -4
- package/src/plugins/prediction-markets/controller/keyboard.ts +1 -1
- package/src/plugins/prediction-markets/controller/live-updates.ts +6 -5
- package/src/plugins/prediction-markets/detail/book.tsx +2 -2
- package/src/plugins/prediction-markets/detail/outcomes.tsx +3 -1
- package/src/plugins/prediction-markets/detail/pane.tsx +3 -1
- package/src/plugins/prediction-markets/detail/trades.tsx +3 -3
- package/src/plugins/registry/context.ts +3 -4
- package/src/plugins/registry/index.ts +5 -6
- package/src/react/input.test.ts +126 -3
- package/src/react/input.ts +120 -1
- package/src/remote/app-host.tsx +2 -13
- package/src/renderers/electrobun/bun/desktop/backend-requests.ts +44 -60
- package/src/renderers/electrobun/bun/desktop/capability-bridge.ts +15 -13
- package/src/renderers/electrobun/bun/desktop/host-requests.ts +26 -22
- package/src/renderers/electrobun/bun/desktop/http-fetch.ts +5 -1
- package/src/renderers/electrobun/bun/desktop/initialization.ts +11 -6
- package/src/renderers/electrobun/bun/desktop/media.ts +5 -3
- package/src/renderers/electrobun/bun/desktop/plugin-state.ts +21 -22
- package/src/renderers/electrobun/bun/desktop/window-controls.ts +3 -1
- package/src/renderers/electrobun/bun/desktop/workspace/requests.ts +18 -18
- package/src/renderers/electrobun/bun/index.ts +123 -83
- package/src/renderers/electrobun/shared/protocol.ts +146 -7
- package/src/renderers/electrobun/view/app-services.ts +5 -8
- package/src/renderers/electrobun/view/backend-rpc.ts +18 -8
- package/src/renderers/electrobun/view/broker-remote-client.ts +2 -2
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +5 -22
- package/src/renderers/electrobun/view/config-host.ts +1 -1
- package/src/renderers/electrobun/view/context-menu.ts +1 -17
- package/src/renderers/electrobun/view/data-table/index.tsx +0 -1
- package/src/renderers/electrobun/view/data-table/row.tsx +0 -4
- package/src/renderers/electrobun/view/desktop/control-styles.ts +37 -34
- package/src/renderers/electrobun/view/desktop/controls.tsx +36 -33
- package/src/renderers/electrobun/view/desktop/list-view.tsx +15 -12
- package/src/renderers/electrobun/view/desktop/popover.tsx +2 -3
- package/src/renderers/electrobun/view/dialog-host.tsx +2 -3
- package/src/renderers/electrobun/view/fatal-screen.tsx +0 -1
- package/src/renderers/electrobun/view/host/box.tsx +0 -1
- package/src/renderers/electrobun/view/host/chart-surface.tsx +0 -1
- package/src/renderers/electrobun/view/host/input.tsx +0 -1
- package/src/renderers/electrobun/view/host/media-surface.tsx +0 -1
- package/src/renderers/electrobun/view/host/native.ts +0 -1
- package/src/renderers/electrobun/view/host/scroll-box.tsx +0 -1
- package/src/renderers/electrobun/view/host/tabs.tsx +0 -1
- package/src/renderers/electrobun/view/host/text.tsx +0 -1
- package/src/renderers/electrobun/view/http-fetch.ts +3 -11
- package/src/renderers/electrobun/view/input-host.tsx +10 -53
- package/src/renderers/electrobun/view/key-event.ts +0 -1
- package/src/renderers/electrobun/view/main.tsx +3 -3
- package/src/renderers/electrobun/view/native-renderer.ts +0 -1
- package/src/renderers/electrobun/view/native-stubs/backend-rpc.ts +13 -1
- package/src/renderers/electrobun/view/native-stubs/chart/surface-manager.ts +11 -0
- package/src/renderers/electrobun/view/native-stubs/native-stubs.test.ts +47 -0
- package/src/renderers/electrobun/view/remote/asset-data-client.ts +6 -44
- package/src/renderers/electrobun/view/remote/persistence.ts +6 -2
- package/src/renderers/electrobun/view/remote/quote-subscription-registry.test.ts +86 -0
- package/src/renderers/electrobun/view/remote/quote-subscription-registry.ts +72 -0
- package/src/renderers/electrobun/view/remote/ticker-repository.ts +2 -2
- package/src/renderers/electrobun/view/toast-host.tsx +0 -1
- package/src/renderers/electrobun/view/ui-host.tsx +1 -2
- package/src/renderers/electrobun/view/update-host.ts +1 -1
- package/src/renderers/opentui/chart-surface.tsx +2 -1
- package/src/renderers/opentui/dialog-host.tsx +20 -4
- package/src/renderers/opentui/image/loader.ts +12 -2
- package/src/renderers/opentui/input-host.tsx +7 -49
- package/src/renderers/opentui/start.tsx +2 -0
- package/src/sources/gloomberb-cloud/history-quality.ts +44 -0
- package/src/sources/gloomberb-cloud/index.test.ts +173 -0
- package/src/sources/gloomberb-cloud/index.ts +42 -20
- package/src/sources/gloomberb-cloud/normalizers.ts +9 -3
- package/src/sources/provider-router/cache.ts +1 -1
- package/src/sources/provider-router/document-routes.ts +10 -5
- package/src/sources/provider-router/financials.test.ts +14 -0
- package/src/sources/provider-router/financials.ts +6 -1
- package/src/sources/provider-router/history.test.ts +163 -1
- package/src/sources/provider-router/history.ts +278 -347
- package/src/sources/provider-router/index.ts +2 -2
- package/src/sources/provider-router/routing.test.ts +39 -0
- package/src/sources/provider-router/routing.ts +24 -11
- package/src/sources/provider-router/supplemental.ts +37 -17
- package/src/sources/sec-edgar/content.ts +2 -12
- package/src/sources/sec-edgar.ts +2 -13
- package/src/sources/yahoo-finance/history.ts +2 -2
- package/src/sources/yahoo-finance/options.ts +5 -0
- package/src/sources/yahoo-finance.ts +2 -2
- package/src/state/app/bootstrap.ts +2 -2
- package/src/state/app/context/index.tsx +2 -2
- package/src/state/hooks/quote-streaming.ts +66 -1
- package/src/state/hooks/session-snapshot.ts +2 -2
- package/src/state/selectors.ts +0 -9
- package/src/sync/controller.test.ts +98 -0
- package/src/sync/controller.ts +29 -5
- package/src/sync/react.ts +2 -2
- package/src/sync/types.ts +2 -2
- package/src/theme/colors.test.ts +10 -0
- package/src/theme/colors.ts +75 -78
- package/src/theme/theme-context.test.tsx +67 -0
- package/src/theme/theme-context.tsx +9 -5
- package/src/tickers/open-target.ts +2 -2
- package/src/tickers/search/upsert.ts +2 -2
- package/src/time-series/alignment.ts +0 -7
- package/src/time-series/chart-data.ts +145 -0
- package/src/time-series/date-window.ts +44 -0
- package/src/time-series/history-window.ts +21 -0
- package/src/time-series/hooks.test.ts +59 -0
- package/src/time-series/hooks.ts +33 -12
- package/src/time-series/market-resolution.ts +2 -2
- package/src/time-series/market.ts +1 -1
- package/src/time-series/range.ts +9 -0
- package/src/{components/chart/core → time-series}/resolution.ts +3 -102
- package/src/time-series/resolve.test.ts +203 -1
- package/src/time-series/resolve.ts +96 -18
- package/src/time-series/spec-studies.test.ts +15 -0
- package/src/time-series/spec.ts +2 -2
- package/src/time-series/studies.ts +5 -2
- package/src/time-series/types.ts +3 -1
- package/src/time-series/use-chart-resolution.test.tsx +358 -0
- package/src/time-series/use-chart-resolution.ts +46 -4
- package/src/types/broker.ts +2 -2
- package/src/types/data-provider.ts +3 -3
- package/src/types/financials.ts +12 -0
- package/src/types/plugin.ts +2 -2
- package/src/ui/context-menu.tsx +3 -2
- package/src/ui/dialog.tsx +2 -2
- package/src/utils/html-entities.ts +3 -5
- package/src/utils/main-thread-monitor.ts +1 -1
- package/src/utils/price-history.ts +5 -5
- package/src/version.ts +3 -1
- package/src/components/chart/core/viewport.test.ts +0 -8
- package/src/components/chart/core/viewport.ts +0 -24
- package/src/time-series/index.ts +0 -14
- /package/src/{components/chart/core → time-series}/resolution.test.ts +0 -0
|
@@ -1,48 +1,13 @@
|
|
|
1
1
|
import type { PricePoint } from "../../../types/financials";
|
|
2
|
+
export type { ChartResolution, TimeRange } from "../../../time-series/range";
|
|
2
3
|
|
|
3
|
-
export type TimeRange = "1D" | "1W" | "1M" | "3M" | "6M" | "1Y" | "5Y" | "ALL";
|
|
4
|
-
export type ChartResolution = "auto" | "1m" | "5m" | "15m" | "30m" | "45m" | "1h" | "1d" | "1wk" | "1mo";
|
|
5
4
|
export type ChartRenderMode = "area" | "line" | "candles" | "ohlc" | "hlc";
|
|
6
5
|
export type ChartAxisMode = "price" | "percent";
|
|
7
6
|
export type ChartRendererPreference = "auto" | "kitty" | "braille";
|
|
8
7
|
export type ResolvedChartRenderer = "kitty" | "braille";
|
|
9
|
-
export type ComparisonChartRenderMode = "area" | "line";
|
|
10
8
|
export type ChartSessionBackgroundKind = "pre" | "post";
|
|
11
9
|
|
|
12
|
-
export interface ChartDateWindow {
|
|
13
|
-
start: Date | null;
|
|
14
|
-
end: Date | null;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export const TIME_RANGES: TimeRange[] = ["1D", "1W", "1M", "3M", "6M", "1Y", "5Y", "ALL"];
|
|
18
|
-
export const CHART_RENDER_MODES: ChartRenderMode[] = ["area", "line", "candles", "ohlc", "hlc"];
|
|
19
10
|
export const CHART_RENDERER_PREFERENCES: ChartRendererPreference[] = ["auto", "kitty", "braille"];
|
|
20
|
-
export const COMPARISON_RENDER_MODES: ComparisonChartRenderMode[] = ["area", "line"];
|
|
21
|
-
|
|
22
|
-
/** Number of trading days for each time range */
|
|
23
|
-
export const RANGE_DAYS: Record<TimeRange, number> = {
|
|
24
|
-
"1D": 1,
|
|
25
|
-
"1W": 5,
|
|
26
|
-
"1M": 21,
|
|
27
|
-
"3M": 63,
|
|
28
|
-
"6M": 126,
|
|
29
|
-
"1Y": 252,
|
|
30
|
-
"5Y": 1260,
|
|
31
|
-
"ALL": Infinity,
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
export interface ChartViewState {
|
|
35
|
-
presetRange: TimeRange;
|
|
36
|
-
bufferRange: TimeRange;
|
|
37
|
-
activePreset: TimeRange | null;
|
|
38
|
-
dateWindow: ChartDateWindow | null;
|
|
39
|
-
resolution: ChartResolution;
|
|
40
|
-
panOffset: number; // data points shifted left from right edge (0 = most recent)
|
|
41
|
-
zoomLevel: number; // 1.0 = full selected range, 2.0 = zoomed in 2x
|
|
42
|
-
cursorX: number | null; // local plot x in cell units; may be fractional with pixel mouse
|
|
43
|
-
cursorY: number | null; // local plot y in cell units; may be fractional with pixel mouse
|
|
44
|
-
renderMode?: ChartRenderMode;
|
|
45
|
-
}
|
|
46
11
|
|
|
47
12
|
export interface Pixel {
|
|
48
13
|
color: string;
|
|
@@ -91,28 +56,6 @@ export interface VisibleWindow {
|
|
|
91
56
|
endIdx: number;
|
|
92
57
|
}
|
|
93
58
|
|
|
94
|
-
export interface ComparisonChartSeries {
|
|
95
|
-
symbol: string;
|
|
96
|
-
color: string;
|
|
97
|
-
fillColor: string;
|
|
98
|
-
currency?: string;
|
|
99
|
-
points: PricePoint[];
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
export interface ComparisonChartViewState {
|
|
103
|
-
presetRange: TimeRange;
|
|
104
|
-
bufferRange: TimeRange;
|
|
105
|
-
activePreset: TimeRange | null;
|
|
106
|
-
dateWindow: ChartDateWindow | null;
|
|
107
|
-
resolution: ChartResolution;
|
|
108
|
-
panOffset: number;
|
|
109
|
-
zoomLevel: number; // 1.0 = full selected range, 2.0 = zoomed in 2x
|
|
110
|
-
cursorX: number | null;
|
|
111
|
-
cursorY: number | null;
|
|
112
|
-
renderMode?: ComparisonChartRenderMode;
|
|
113
|
-
selectedSymbol: string | null;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
59
|
import type { OverlayPoint, OscillatorPoint, MacdResult, BollingerResult } from "../indicators/types";
|
|
117
60
|
|
|
118
61
|
export interface ChartIndicatorOverlays {
|
|
@@ -4,10 +4,8 @@ interface ChartCursorPosition {
|
|
|
4
4
|
y: number | null;
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
-
export type ChartCursorMotionKind = "pixel" | "cell" | "discrete";
|
|
8
|
-
|
|
9
7
|
const CELL_CURSOR_EASING = 0.72;
|
|
10
|
-
|
|
8
|
+
const CELL_CURSOR_SNAP_DISTANCE = 0.035;
|
|
11
9
|
|
|
12
10
|
function sameNullableNumber(left: number | null, right: number | null, epsilon = 0): boolean {
|
|
13
11
|
if (left === right) return true;
|
|
@@ -15,7 +13,7 @@ function sameNullableNumber(left: number | null, right: number | null, epsilon =
|
|
|
15
13
|
return Math.abs(left - right) <= epsilon;
|
|
16
14
|
}
|
|
17
15
|
|
|
18
|
-
|
|
16
|
+
function sameCursorPosition(
|
|
19
17
|
left: ChartCursorPosition,
|
|
20
18
|
right: ChartCursorPosition,
|
|
21
19
|
epsilon = 0,
|
|
@@ -24,12 +24,3 @@ export interface BollingerResult {
|
|
|
24
24
|
middle: OverlayPoint[];
|
|
25
25
|
lower: OverlayPoint[];
|
|
26
26
|
}
|
|
27
|
-
|
|
28
|
-
/** Active indicator configuration for a chart pane */
|
|
29
|
-
export interface IndicatorConfig {
|
|
30
|
-
sma?: number[]; // e.g. [20, 50, 200]
|
|
31
|
-
ema?: number[]; // e.g. [12, 26]
|
|
32
|
-
rsi?: number | null; // e.g. 14
|
|
33
|
-
macd?: { fast: number; slow: number; signal: number } | null;
|
|
34
|
-
bollinger?: { period: number; stdDev: number } | null;
|
|
35
|
-
}
|
|
@@ -136,17 +136,6 @@ export function resolveChartMarketSession(sources: readonly MarketSessionSource[
|
|
|
136
136
|
return hasSupportedSource ? US_EXTENDED_HOURS_SESSION : null;
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
-
export function getChartMarketSessionKey(session: ChartMarketSession | null | undefined): string {
|
|
140
|
-
if (!session) return "session:none";
|
|
141
|
-
return [
|
|
142
|
-
session.timeZone,
|
|
143
|
-
session.preMarketStartMinutes,
|
|
144
|
-
session.regularStartMinutes,
|
|
145
|
-
session.regularEndMinutes,
|
|
146
|
-
session.postMarketEndMinutes,
|
|
147
|
-
].join(":");
|
|
148
|
-
}
|
|
149
|
-
|
|
150
139
|
export function resolveExtendedHoursBackgroundSpans(
|
|
151
140
|
values: readonly (Date | string | number)[],
|
|
152
141
|
session: ChartMarketSession | null | undefined,
|
|
@@ -55,7 +55,7 @@ export function encodeKittyTransmitRgba(options: KittyTransmitOptions): string[]
|
|
|
55
55
|
// ponytail: level 3 compresses chart pixels ~2.5x faster than the default for
|
|
56
56
|
// ~40% more bytes; crosshair moves retransmit the whole plot every frame, so
|
|
57
57
|
// CPU is the constraint on a local pty. Raise it if bandwidth ever is.
|
|
58
|
-
const compressed = deflateSync(
|
|
58
|
+
const compressed = deflateSync(options.rgba, { level: 3 });
|
|
59
59
|
const chunks = chunkBase64Payload(compressed.toString("base64"), options.chunkSize);
|
|
60
60
|
|
|
61
61
|
return chunks.map((chunk, index) => {
|
|
@@ -22,15 +22,6 @@ export function getChartPixelLayout(scene: ChartScene, pixelWidth: number, pixel
|
|
|
22
22
|
};
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
export function getComparisonPixelLayout(pixelWidth: number, pixelHeight: number) {
|
|
26
|
-
return {
|
|
27
|
-
plotLeft: 0,
|
|
28
|
-
plotTop: 0,
|
|
29
|
-
plotRight: Math.max(pixelWidth - 1, 0),
|
|
30
|
-
plotBottom: Math.max(pixelHeight - 1, 0),
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
|
|
34
25
|
export function projectX(index: number, count: number, left: number, right: number): number {
|
|
35
26
|
if (count <= 1) return (left + right) / 2;
|
|
36
27
|
return lerp(left, right, index / (count - 1));
|
|
@@ -40,7 +31,9 @@ export function isOhlcLikeMode(mode: ChartRenderMode): boolean {
|
|
|
40
31
|
return mode === "ohlc" || mode === "hlc";
|
|
41
32
|
}
|
|
42
33
|
|
|
43
|
-
export function isHighLowMode(
|
|
34
|
+
export function isHighLowMode(
|
|
35
|
+
mode: ChartRenderMode,
|
|
36
|
+
): mode is Extract<ChartRenderMode, "candles" | "ohlc" | "hlc"> {
|
|
44
37
|
return mode === "candles" || isOhlcLikeMode(mode);
|
|
45
38
|
}
|
|
46
39
|
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { renderToStaticMarkup } from "react-dom/server";
|
|
3
|
+
import {
|
|
4
|
+
UiHostProvider,
|
|
5
|
+
type RendererHost,
|
|
6
|
+
type UiHost,
|
|
7
|
+
} from "../../../../ui";
|
|
8
|
+
import { WebBox } from "../../../../renderers/electrobun/view/host/box";
|
|
9
|
+
import { WebText } from "../../../../renderers/electrobun/view/host/text";
|
|
10
|
+
import { StaticXAxisLabels } from "./axis-overlays";
|
|
11
|
+
|
|
12
|
+
const renderer: RendererHost = {
|
|
13
|
+
requestExit() {},
|
|
14
|
+
async openExternal() {},
|
|
15
|
+
async copyText() {},
|
|
16
|
+
async readText() {
|
|
17
|
+
return "";
|
|
18
|
+
},
|
|
19
|
+
notify() {},
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
function renderAxis(kind: "opentui" | "desktop-web"): string {
|
|
23
|
+
const ui = {
|
|
24
|
+
kind,
|
|
25
|
+
capabilities: {
|
|
26
|
+
cellWidthPx: 8,
|
|
27
|
+
fractionalViewport: kind === "desktop-web",
|
|
28
|
+
},
|
|
29
|
+
Box: WebBox,
|
|
30
|
+
Text: WebText,
|
|
31
|
+
} as unknown as UiHost;
|
|
32
|
+
const fallback = "Nov 3 2025 Mar Jul 29 2026";
|
|
33
|
+
return renderToStaticMarkup(
|
|
34
|
+
<UiHostProvider ui={ui} renderer={renderer}>
|
|
35
|
+
<StaticXAxisLabels
|
|
36
|
+
labels={[fallback]}
|
|
37
|
+
positionedLabels={[
|
|
38
|
+
{ label: "Nov 3 2025", ratio: 0 },
|
|
39
|
+
{ label: "Mar", ratio: 0.5 },
|
|
40
|
+
{ label: "Jul 29 2026", ratio: 1 },
|
|
41
|
+
]}
|
|
42
|
+
width={80}
|
|
43
|
+
/>
|
|
44
|
+
</UiHostProvider>,
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
describe("StaticXAxisLabels", () => {
|
|
49
|
+
test("positions desktop labels by chart ratio instead of font-space advances", () => {
|
|
50
|
+
const html = renderAxis("desktop-web");
|
|
51
|
+
|
|
52
|
+
expect(html).toContain("left:50%");
|
|
53
|
+
expect(html).toContain("transform:translateX(-50%)");
|
|
54
|
+
expect(html).toContain("right:0");
|
|
55
|
+
expect(html).not.toContain("Nov 3 2025 Mar");
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test("keeps the fixed-width axis string for terminal cells", () => {
|
|
59
|
+
const html = renderAxis("opentui");
|
|
60
|
+
|
|
61
|
+
expect(html).toContain("Nov 3 2025 Mar");
|
|
62
|
+
expect(html).not.toContain("left:50%");
|
|
63
|
+
});
|
|
64
|
+
});
|
|
@@ -8,6 +8,11 @@ export interface StaticChartXMarker {
|
|
|
8
8
|
lineChar?: string;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
export interface StaticChartXAxisLabel {
|
|
12
|
+
label: string;
|
|
13
|
+
ratio: number;
|
|
14
|
+
}
|
|
15
|
+
|
|
11
16
|
export function clampRatio(value: number): number {
|
|
12
17
|
if (!Number.isFinite(value)) return 0;
|
|
13
18
|
return Math.max(0, Math.min(1, value));
|
|
@@ -28,6 +33,7 @@ function alignAxisLabel(label: string, width: number, index: number, count: numb
|
|
|
28
33
|
|
|
29
34
|
export function StaticXAxisLabels({
|
|
30
35
|
labels,
|
|
36
|
+
positionedLabels,
|
|
31
37
|
width,
|
|
32
38
|
color,
|
|
33
39
|
cursorColumn,
|
|
@@ -37,6 +43,7 @@ export function StaticXAxisLabels({
|
|
|
37
43
|
cursorBackgroundColor,
|
|
38
44
|
}: {
|
|
39
45
|
labels: string[];
|
|
46
|
+
positionedLabels?: readonly StaticChartXAxisLabel[];
|
|
40
47
|
width: number;
|
|
41
48
|
color?: string;
|
|
42
49
|
cursorColumn?: number | null;
|
|
@@ -45,11 +52,17 @@ export function StaticXAxisLabels({
|
|
|
45
52
|
cursorColor?: string;
|
|
46
53
|
cursorBackgroundColor?: string;
|
|
47
54
|
}) {
|
|
55
|
+
const uiHost = useUiHost();
|
|
48
56
|
const { cellWidthPx = 8, fractionalViewport = false } = useUiCapabilities();
|
|
49
57
|
const visibleLabels = labels.filter(Boolean);
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
58
|
+
const visiblePositionedLabels = positionedLabels?.filter((entry) => (
|
|
59
|
+
entry.label.length > 0 && Number.isFinite(entry.ratio)
|
|
60
|
+
)) ?? [];
|
|
61
|
+
if (visibleLabels.length === 0 && visiblePositionedLabels.length === 0) return null;
|
|
62
|
+
if (width <= 0) return null;
|
|
63
|
+
const segmentCount = Math.max(visibleLabels.length, 1);
|
|
64
|
+
const baseWidth = Math.floor(width / segmentCount);
|
|
65
|
+
let remainder = width - baseWidth * segmentCount;
|
|
53
66
|
const clippedCursorLabel = cursorLabel ? cursorLabel.slice(0, width) : null;
|
|
54
67
|
const cursorLabelWidth = clippedCursorLabel?.length ?? 0;
|
|
55
68
|
const usePixelOverlay = fractionalViewport
|
|
@@ -83,17 +96,49 @@ export function StaticXAxisLabels({
|
|
|
83
96
|
position="relative"
|
|
84
97
|
overflow="hidden"
|
|
85
98
|
>
|
|
86
|
-
|
|
87
|
-
{
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
99
|
+
{uiHost.kind === "desktop-web" && visiblePositionedLabels.length > 0 ? (
|
|
100
|
+
<Box position="absolute" left={0} top={0} width={width} height={1}>
|
|
101
|
+
{visiblePositionedLabels.map((entry, index) => {
|
|
102
|
+
const ratio = clampRatio(entry.ratio);
|
|
103
|
+
const edgeStyle = ratio <= 0
|
|
104
|
+
? { left: 0 }
|
|
105
|
+
: ratio >= 1
|
|
106
|
+
? { right: 0 }
|
|
107
|
+
: {
|
|
108
|
+
left: `${ratio * 100}%`,
|
|
109
|
+
transform: "translateX(-50%)",
|
|
110
|
+
};
|
|
111
|
+
return (
|
|
112
|
+
<Text
|
|
113
|
+
key={`${entry.label}:${entry.ratio}:${index}`}
|
|
114
|
+
fg={color}
|
|
115
|
+
selectable={false}
|
|
116
|
+
style={{
|
|
117
|
+
position: "absolute",
|
|
118
|
+
top: 0,
|
|
119
|
+
whiteSpace: "pre",
|
|
120
|
+
pointerEvents: "none",
|
|
121
|
+
...edgeStyle,
|
|
122
|
+
}}
|
|
123
|
+
>
|
|
124
|
+
{entry.label}
|
|
125
|
+
</Text>
|
|
126
|
+
);
|
|
127
|
+
})}
|
|
128
|
+
</Box>
|
|
129
|
+
) : (
|
|
130
|
+
<Box width={width} height={1} flexDirection="row">
|
|
131
|
+
{visibleLabels.map((label, index) => {
|
|
132
|
+
const cellWidth = baseWidth + (remainder > 0 ? 1 : 0);
|
|
133
|
+
remainder -= remainder > 0 ? 1 : 0;
|
|
134
|
+
return (
|
|
135
|
+
<Box key={`${label}:${index}`} width={cellWidth} overflow="hidden">
|
|
136
|
+
<Text fg={color}>{alignAxisLabel(label, cellWidth, index, visibleLabels.length)}</Text>
|
|
137
|
+
</Box>
|
|
138
|
+
);
|
|
139
|
+
})}
|
|
140
|
+
</Box>
|
|
141
|
+
)}
|
|
97
142
|
{clippedCursorLabel && (cursorLeftPercent !== null || cursorLeft !== null) ? (
|
|
98
143
|
<Text
|
|
99
144
|
fg={cursorColor}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { useCallback, useMemo, useRef, useState } from "react";
|
|
2
2
|
import { Box, ChartSurface, Text, type BoxRenderable, type ChartSurfaceProps, useUiCapabilities } from "../../../../ui";
|
|
3
|
-
import { colors as themeColors } from "../../../../theme/colors";
|
|
4
3
|
import { useThemeColors } from "../../../../theme/theme-context";
|
|
5
4
|
import { PriceAxisLabels } from "../../price-axis-labels";
|
|
6
5
|
import type { ProjectedChartPoint } from "../../core/data";
|
|
@@ -102,7 +101,7 @@ export function StaticChartSurface({
|
|
|
102
101
|
yAxisColor,
|
|
103
102
|
formatYAxisValue,
|
|
104
103
|
}: StaticChartSurfaceProps) {
|
|
105
|
-
useThemeColors();
|
|
104
|
+
const themeColors = useThemeColors();
|
|
106
105
|
const { cellWidthPx = 8, cellHeightPx = 18 } = useUiCapabilities();
|
|
107
106
|
const plotRef = useRef<BoxRenderable | null>(null);
|
|
108
107
|
const [cursor, setCursor] = useState<{ x: number; y: number } | null>(null);
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
type MutableRefObject,
|
|
5
5
|
type SetStateAction,
|
|
6
6
|
} from "react";
|
|
7
|
-
import type {
|
|
7
|
+
import type { AppTickerRepositoryPort } from "../../core/app-service-ports";
|
|
8
8
|
import type { PluginRegistry } from "../../plugins/registry";
|
|
9
9
|
import type { AppAction, AppState } from "../../state/app/context";
|
|
10
10
|
import type { DataProvider } from "../../types/data-provider";
|
|
@@ -45,7 +45,7 @@ interface UseCommandBarActionRuntimeOptions {
|
|
|
45
45
|
state: AppState;
|
|
46
46
|
stateRef: MutableRefObject<AppState>;
|
|
47
47
|
themePickerRef: MutableRefObject<ThemePickerHandle | null>;
|
|
48
|
-
tickerRepository:
|
|
48
|
+
tickerRepository: AppTickerRepositoryPort;
|
|
49
49
|
tickers: AppState["tickers"];
|
|
50
50
|
updateTopRoute: (updater: (route: CommandBarRoute) => CommandBarRoute) => void;
|
|
51
51
|
}
|
|
@@ -248,7 +248,7 @@ export function runDirectCommandAction(options: {
|
|
|
248
248
|
persistConfig(nextConfig);
|
|
249
249
|
applyLanguagePreference(next);
|
|
250
250
|
const languageLabel = next === "auto" ? t(LANGUAGE_DISPLAY_NAMES.auto) : LANGUAGE_DISPLAY_NAMES[next];
|
|
251
|
-
notify(`${t("Language")}: ${languageLabel}
|
|
251
|
+
notify(`${t("Language")}: ${languageLabel}`, { type: "success" });
|
|
252
252
|
closeAll({ revertThemePreview: false });
|
|
253
253
|
return;
|
|
254
254
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Box, Text, TextAttributes } from "../../../ui";
|
|
2
|
-
import { colors } from "../../../theme/colors";
|
|
3
2
|
import { useThemeColors } from "../../../theme/theme-context";
|
|
4
3
|
import { Button, Spinner } from "../../ui";
|
|
5
4
|
import {
|
|
@@ -281,6 +280,7 @@ function CommandBarConfirmBody({
|
|
|
281
280
|
queryDisplayWidth: number;
|
|
282
281
|
onConfirm: () => void;
|
|
283
282
|
}) {
|
|
283
|
+
const themeColors = useThemeColors();
|
|
284
284
|
return (
|
|
285
285
|
<Box flexDirection="column" height={bodyHeight} paddingX={contentPadding}>
|
|
286
286
|
{route.body.map((line, index) => (
|
|
@@ -291,7 +291,7 @@ function CommandBarConfirmBody({
|
|
|
291
291
|
<Box height={1} />
|
|
292
292
|
{route.error && (
|
|
293
293
|
<Box height={1}>
|
|
294
|
-
<Text fg={
|
|
294
|
+
<Text fg={themeColors.negative}>{truncateText(route.error, queryDisplayWidth)}</Text>
|
|
295
295
|
</Box>
|
|
296
296
|
)}
|
|
297
297
|
{route.pending && (
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
commandBarSubtleText,
|
|
12
12
|
commandBarText,
|
|
13
13
|
} from "../../../theme/colors";
|
|
14
|
+
import { useThemeColors } from "../../../theme/theme-context";
|
|
14
15
|
import { CommandBarPanelBody } from "./body";
|
|
15
16
|
import type { CommandBarPanelProps } from "./types";
|
|
16
17
|
|
|
@@ -68,15 +69,16 @@ export function CommandBarPanel({
|
|
|
68
69
|
visibleListState,
|
|
69
70
|
workflowScrollRef,
|
|
70
71
|
}: CommandBarPanelProps) {
|
|
71
|
-
const
|
|
72
|
-
const
|
|
73
|
-
const
|
|
74
|
-
const
|
|
75
|
-
const
|
|
76
|
-
const
|
|
77
|
-
const
|
|
78
|
-
const
|
|
79
|
-
const
|
|
72
|
+
const colors = useThemeColors();
|
|
73
|
+
const paletteBg = commandBarBg(colors);
|
|
74
|
+
const paletteHeadingText = commandBarHeadingText(colors);
|
|
75
|
+
const paletteHoverBg = commandBarHoverBg(colors);
|
|
76
|
+
const paletteSelectedBg = commandBarSelectedBg(colors);
|
|
77
|
+
const paletteSelectedText = commandBarSelectedText(colors);
|
|
78
|
+
const paletteText = commandBarText(colors);
|
|
79
|
+
const paletteSubtleText = commandBarSubtleText(colors);
|
|
80
|
+
const panelBg = nativePaneChrome ? commandBarPanelBg(colors) : paletteBg;
|
|
81
|
+
const inputBg = nativePaneChrome ? commandBarInputBg(colors) : paletteBg;
|
|
80
82
|
|
|
81
83
|
useLayoutEffect(() => {
|
|
82
84
|
const scrollBox = nativeListScrollRef.current;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useCallback, useEffect, useRef } from "react";
|
|
2
2
|
import type { AppState } from "../../../../state/app/context";
|
|
3
|
-
import type {
|
|
3
|
+
import type { AppTickerRepositoryPort } from "../../../../core/app-service-ports";
|
|
4
4
|
import type { PluginRegistry } from "../../../../plugins/registry";
|
|
5
5
|
import {
|
|
6
6
|
rankTickerSearchItems,
|
|
@@ -19,7 +19,7 @@ interface UseCommandBarTickerSearchActionsOptions {
|
|
|
19
19
|
dispatch: (action: any) => void;
|
|
20
20
|
focusTicker: (symbol: string, options?: { forceNewPane?: boolean }) => void;
|
|
21
21
|
pluginRegistry: Pick<PluginRegistry, "events">;
|
|
22
|
-
tickerRepository:
|
|
22
|
+
tickerRepository: AppTickerRepositoryPort;
|
|
23
23
|
tickers: AppState["tickers"];
|
|
24
24
|
}
|
|
25
25
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useCallback } from "react";
|
|
2
2
|
import type { DataProvider } from "../../../types/data-provider";
|
|
3
|
-
import type {
|
|
3
|
+
import type { AppTickerRepositoryPort } from "../../../core/app-service-ports";
|
|
4
4
|
import type { PluginRegistry } from "../../../plugins/registry";
|
|
5
5
|
import type { LayoutBounds } from "../../../plugins/pane-manager";
|
|
6
6
|
import { useRouteListState } from "../routing/list-state";
|
|
@@ -16,7 +16,7 @@ import { useCommandBarActionRuntime } from "../action-runtime";
|
|
|
16
16
|
|
|
17
17
|
interface CommandBarProps {
|
|
18
18
|
dataProvider: DataProvider;
|
|
19
|
-
tickerRepository:
|
|
19
|
+
tickerRepository: AppTickerRepositoryPort;
|
|
20
20
|
pluginRegistry: PluginRegistry;
|
|
21
21
|
quitApp: () => void;
|
|
22
22
|
onCheckForUpdates?: () => void | Promise<void>;
|
|
@@ -99,12 +99,12 @@ export function CommandBarWorkflowBody({
|
|
|
99
99
|
<>
|
|
100
100
|
{route.subtitle && (
|
|
101
101
|
<Box height={1}>
|
|
102
|
-
<Text fg={paletteSubtleText}>{truncateText(route.subtitle, queryDisplayWidth)}</Text>
|
|
102
|
+
<Text fg={paletteSubtleText}>{truncateText(t(route.subtitle), queryDisplayWidth)}</Text>
|
|
103
103
|
</Box>
|
|
104
104
|
)}
|
|
105
105
|
{route.description?.map((line, index) => (
|
|
106
106
|
<Box key={`workflow-desc:${index}`} height={1}>
|
|
107
|
-
<Text fg={paletteSubtleText}>{truncateText(line, queryDisplayWidth)}</Text>
|
|
107
|
+
<Text fg={paletteSubtleText}>{truncateText(t(line), queryDisplayWidth)}</Text>
|
|
108
108
|
</Box>
|
|
109
109
|
))}
|
|
110
110
|
{route.subtitle || (route.description?.length ?? 0) > 0 ? <Box height={1} /> : null}
|
|
@@ -144,7 +144,7 @@ export function CommandBarWorkflowBody({
|
|
|
144
144
|
)}
|
|
145
145
|
{route.pendingLabel && route.pending && (
|
|
146
146
|
<Box height={1}>
|
|
147
|
-
<Spinner label={route.pendingLabel} />
|
|
147
|
+
<Spinner label={t(route.pendingLabel)} />
|
|
148
148
|
</Box>
|
|
149
149
|
)}
|
|
150
150
|
{!nativePaneChrome && <Box flexGrow={1} />}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Dispatch } from "react";
|
|
2
2
|
import type { DataProvider } from "../../../types/data-provider";
|
|
3
|
-
import type {
|
|
3
|
+
import type { AppTickerRepositoryPort } from "../../../core/app-service-ports";
|
|
4
4
|
import type { PluginRegistry } from "../../../plugins/registry";
|
|
5
5
|
import type { AppAction, AppState } from "../../../state/app/context";
|
|
6
6
|
import {
|
|
@@ -46,7 +46,7 @@ export function createCommandBarCollectionWorkflowActions(options: {
|
|
|
46
46
|
persistConfig: (nextConfig: AppState["config"]) => void;
|
|
47
47
|
pluginRegistry: PluginRegistry;
|
|
48
48
|
setActiveCollection: (collectionId: string) => void;
|
|
49
|
-
tickerRepository:
|
|
49
|
+
tickerRepository: AppTickerRepositoryPort;
|
|
50
50
|
}): CommandBarCollectionWorkflowActions {
|
|
51
51
|
const {
|
|
52
52
|
activeCollectionId,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useCallback, useMemo, type Dispatch, type MutableRefObject, type SetStateAction } from "react";
|
|
2
2
|
import type { DataProvider } from "../../../types/data-provider";
|
|
3
|
-
import type {
|
|
3
|
+
import type { AppTickerRepositoryPort } from "../../../core/app-service-ports";
|
|
4
4
|
import type { PluginRegistry } from "../../../plugins/registry";
|
|
5
5
|
import type { AppAction, AppState } from "../../../state/app/context";
|
|
6
6
|
import type { TickerRecord } from "../../../types/ticker";
|
|
@@ -37,7 +37,7 @@ interface UseCommandBarWorkflowCoordinatorOptions {
|
|
|
37
37
|
setActiveCollection: (collectionId: string) => void;
|
|
38
38
|
setRouteStack: Dispatch<SetStateAction<CommandBarRoute[]>>;
|
|
39
39
|
stateRef: MutableRefObject<AppState>;
|
|
40
|
-
tickerRepository:
|
|
40
|
+
tickerRepository: AppTickerRepositoryPort;
|
|
41
41
|
updateTopRoute: (updater: (route: CommandBarRoute) => CommandBarRoute) => void;
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -79,6 +79,8 @@ export function CommandBarWorkflowFieldRow({
|
|
|
79
79
|
const fieldBg = nativePaneChrome ? "transparent" : active ? inputBg : panelBg;
|
|
80
80
|
const useNativeSelect = nativePaneChrome && field.type === "select";
|
|
81
81
|
const fieldDescription = getWorkflowFieldDescription(field, active);
|
|
82
|
+
const fieldLabel = t(field.label);
|
|
83
|
+
const translatedFieldDescription = translateWorkflowFieldDescription(fieldDescription);
|
|
82
84
|
const submitOrMoveNext = () => {
|
|
83
85
|
if (isLastField) {
|
|
84
86
|
void onSubmit(route);
|
|
@@ -96,7 +98,7 @@ export function CommandBarWorkflowFieldRow({
|
|
|
96
98
|
|
|
97
99
|
useRemoteUiNode({
|
|
98
100
|
role: "command-bar-field",
|
|
99
|
-
label:
|
|
101
|
+
label: fieldLabel,
|
|
100
102
|
disabled: route.pending,
|
|
101
103
|
actions: {
|
|
102
104
|
focus: focusOrOpenField,
|
|
@@ -106,12 +108,12 @@ export function CommandBarWorkflowFieldRow({
|
|
|
106
108
|
metadata: {
|
|
107
109
|
scope: "command-bar",
|
|
108
110
|
surface: "workflow",
|
|
109
|
-
routeTitle: route.title,
|
|
111
|
+
routeTitle: t(route.title),
|
|
110
112
|
fieldId: field.id,
|
|
111
113
|
fieldType: field.type,
|
|
112
114
|
active,
|
|
113
115
|
value: summarizeWorkflowFieldValue(field, value),
|
|
114
|
-
description:
|
|
116
|
+
description: translatedFieldDescription,
|
|
115
117
|
},
|
|
116
118
|
});
|
|
117
119
|
|
|
@@ -132,7 +134,7 @@ export function CommandBarWorkflowFieldRow({
|
|
|
132
134
|
>
|
|
133
135
|
<Box height={1}>
|
|
134
136
|
<Text fg={active ? paletteText : paletteSubtleText} attributes={active ? TextAttributes.BOLD : 0}>
|
|
135
|
-
{
|
|
137
|
+
{fieldLabel}
|
|
136
138
|
</Text>
|
|
137
139
|
</Box>
|
|
138
140
|
{isWorkflowTextField(field) ? (
|
|
@@ -140,7 +142,7 @@ export function CommandBarWorkflowFieldRow({
|
|
|
140
142
|
<NumberField
|
|
141
143
|
inputRef={getWorkflowInputRef(field.id) as RefObject<InputRenderable | null>}
|
|
142
144
|
value={coerceFieldString(value)}
|
|
143
|
-
placeholder={field.placeholder}
|
|
145
|
+
placeholder={field.placeholder ? t(field.placeholder) : undefined}
|
|
144
146
|
focused={active && !route.pending}
|
|
145
147
|
variant="default"
|
|
146
148
|
backgroundColor={nativePaneChrome ? inputBg : fieldBg}
|
|
@@ -175,7 +177,7 @@ export function CommandBarWorkflowFieldRow({
|
|
|
175
177
|
/>
|
|
176
178
|
) : (
|
|
177
179
|
<Box flexDirection="column" paddingX={1} paddingY={0}>
|
|
178
|
-
{buildTextareaPreviewLines(coerceFieldString(value), field.placeholder, queryDisplayWidth).map((line, index) => (
|
|
180
|
+
{buildTextareaPreviewLines(coerceFieldString(value), field.placeholder ? t(field.placeholder) : undefined, queryDisplayWidth).map((line, index) => (
|
|
179
181
|
<Box key={`${field.id}:preview:${index}`} height={1}>
|
|
180
182
|
<Text fg={coerceFieldString(value).trim() ? paletteText : paletteSubtleText}>{line || " "}</Text>
|
|
181
183
|
</Box>
|
|
@@ -188,7 +190,7 @@ export function CommandBarWorkflowFieldRow({
|
|
|
188
190
|
inputRef={getWorkflowInputRef(field.id) as RefObject<InputRenderable | null>}
|
|
189
191
|
type={field.type === "password" ? "password" : "text"}
|
|
190
192
|
value={coerceFieldString(value)}
|
|
191
|
-
placeholder={field.placeholder}
|
|
193
|
+
placeholder={field.placeholder ? t(field.placeholder) : undefined}
|
|
192
194
|
focused={active && !route.pending}
|
|
193
195
|
variant="default"
|
|
194
196
|
backgroundColor={nativePaneChrome ? inputBg : fieldBg}
|
|
@@ -199,7 +201,11 @@ export function CommandBarWorkflowFieldRow({
|
|
|
199
201
|
) : useNativeSelect ? (
|
|
200
202
|
<NativeSelect
|
|
201
203
|
value={coerceFieldString(value)}
|
|
202
|
-
options={field.options
|
|
204
|
+
options={field.options.map((option) => ({
|
|
205
|
+
...option,
|
|
206
|
+
label: t(option.label),
|
|
207
|
+
description: option.description ? t(option.description) : undefined,
|
|
208
|
+
}))}
|
|
203
209
|
width="100%"
|
|
204
210
|
selectRef={(element) => onNativeSelectRef(field.id, element)}
|
|
205
211
|
onFocus={() => onFieldFocus(field.id)}
|
|
@@ -216,14 +222,14 @@ export function CommandBarWorkflowFieldRow({
|
|
|
216
222
|
style={nativePaneChrome ? { borderRadius: 4 } : undefined}
|
|
217
223
|
>
|
|
218
224
|
<Text fg={active ? paletteText : paletteSubtleText}>
|
|
219
|
-
{truncateText(summarizeWorkflowFieldValue(field, value), queryDisplayWidth)}
|
|
225
|
+
{truncateText(t(summarizeWorkflowFieldValue(field, value)), queryDisplayWidth)}
|
|
220
226
|
</Text>
|
|
221
227
|
</Box>
|
|
222
228
|
)}
|
|
223
|
-
{
|
|
229
|
+
{translatedFieldDescription && (
|
|
224
230
|
<Box height={1}>
|
|
225
231
|
<Text fg={paletteSubtleText}>
|
|
226
|
-
{truncateText(
|
|
232
|
+
{truncateText(translatedFieldDescription, queryDisplayWidth)}
|
|
227
233
|
</Text>
|
|
228
234
|
</Box>
|
|
229
235
|
)}
|
|
@@ -231,6 +237,14 @@ export function CommandBarWorkflowFieldRow({
|
|
|
231
237
|
);
|
|
232
238
|
}
|
|
233
239
|
|
|
240
|
+
function translateWorkflowFieldDescription(description: string | null): string | null {
|
|
241
|
+
if (!description) return null;
|
|
242
|
+
const submitSuffix = " Ctrl+S submits.";
|
|
243
|
+
return description.endsWith(submitSuffix)
|
|
244
|
+
? `${t(description.slice(0, -submitSuffix.length))} ${t(submitSuffix.trim())}`
|
|
245
|
+
: t(description);
|
|
246
|
+
}
|
|
247
|
+
|
|
234
248
|
function buildTextareaPreviewLines(value: string, placeholder: string | undefined, queryDisplayWidth: number): string[] {
|
|
235
249
|
const preview = value.trim();
|
|
236
250
|
return (preview || placeholder || t("Unset"))
|