@gloom-sh/terminal 0.19.2 → 0.19.3
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 -1
- package/package.json +1 -1
- package/patches/electrobun@1.18.1.patch +108 -1
- package/src/account/upgrade-dialog.tsx +4 -23
- package/src/api-client/coalesce.ts +118 -0
- package/src/api-client/credit-boards.ts +13 -0
- package/src/api-client/crypto-etf-flows.ts +6 -0
- package/src/api-client/crypto-markets.ts +40 -0
- package/src/api-client/data.ts +201 -14
- package/src/api-client/equity-screener.ts +10 -0
- package/src/api-client/errors.ts +20 -0
- package/src/api-client/gpu.ts +29 -0
- package/src/api-client/index.ts +5 -2
- package/src/api-client/plan-access.ts +10 -1
- package/src/api-client/plan-rules.ts +35 -0
- package/src/api-client/research-activity.ts +1 -32
- package/src/api-client/types.ts +21 -1
- package/src/app/attention-notice.tsx +94 -0
- package/src/app.tsx +23 -1
- package/src/architecture/core-builtin-allowlist.json +2 -1
- package/src/capabilities/factories.ts +1 -0
- package/src/cli/ascii-output.ts +42 -0
- package/src/cli/base-converter.ts +10 -2
- package/src/cli/command-options.ts +16 -1
- package/src/cli/commands/crypto-hints.ts +23 -4
- package/src/cli/commands/market.ts +92 -23
- package/src/cli/commands/news-search.ts +24 -5
- package/src/cli/commands/overview.ts +9 -4
- package/src/cli/commands/search.ts +71 -12
- package/src/cli/commands/system.ts +22 -30
- package/src/cli/commands/ticker.ts +49 -9
- package/src/cli/commands/version.ts +33 -0
- package/src/cli/context.ts +5 -9
- package/src/cli/data-dir.ts +7 -0
- package/src/cli/desktop-pane-shot-api-policy.ts +85 -0
- package/src/cli/desktop-pane-shot-browser.ts +320 -0
- package/src/cli/desktop-pane-shot-routes.ts +26 -1
- package/src/cli/desktop-pane-shot.ts +196 -256
- package/src/cli/early-command.ts +42 -0
- package/src/cli/earnings-calendar.ts +9 -0
- package/src/cli/entry.ts +19 -13
- package/src/cli/errors.ts +12 -2
- package/src/cli/help.ts +1 -1
- package/src/cli/history-export.ts +22 -2
- package/src/cli/history-rows.ts +154 -4
- package/src/cli/index.ts +18 -1
- package/src/cli/known-gaps.ts +40 -5
- package/src/cli/listing-arg.ts +46 -9
- package/src/cli/options.ts +1 -1
- package/src/cli/output-file.ts +60 -13
- package/src/cli/pane-functions/catalog.ts +14 -3
- package/src/cli/pane-functions/data.ts +1 -1
- package/src/cli/pane-functions/dom.ts +45 -0
- package/src/cli/pane-functions/freshness.ts +46 -9
- package/src/cli/pane-functions/function-help.ts +17 -9
- package/src/cli/pane-functions/headless.ts +22 -14
- package/src/cli/pane-functions/index.ts +6 -2
- package/src/cli/pane-functions/options.ts +6 -2
- package/src/cli/pane-functions/resolver.ts +27 -5
- package/src/cli/pane-functions/screenshot-assessment.ts +33 -0
- package/src/cli/pane-functions/screenshot-bridge.ts +94 -13
- package/src/cli/pane-functions/screenshot-http.ts +70 -0
- package/src/cli/pane-functions/screenshot-render.ts +19 -5
- package/src/cli/quote-answer.ts +20 -0
- package/src/cli/registry.ts +41 -13
- package/src/cli/result.ts +12 -6
- package/src/cli/ticker-resolution.ts +2 -1
- package/src/cli/types.ts +2 -0
- package/src/components/chart/composite/format.ts +3 -0
- package/src/components/chart-table/header.tsx +1 -1
- package/src/components/chart-table/layout.ts +28 -11
- package/src/components/command-bar/action-runtime.ts +4 -0
- package/src/components/command-bar/commands/direct/index.ts +18 -33
- package/src/components/command-bar/commands/direct/runtime.ts +5 -0
- package/src/components/command-bar/commands/registry.ts +10 -1
- package/src/components/command-bar/routes/root/command-items.ts +9 -4
- package/src/components/command-bar/routes/root/runtime.ts +24 -1
- package/src/components/command-bar/surface/index.tsx +9 -3
- package/src/components/company-logo.tsx +2 -1
- package/src/components/layout/header.tsx +8 -3
- package/src/components/layout/market-summary.ts +25 -7
- package/src/components/layout/pane/footer/index.tsx +7 -2
- package/src/components/layout/pane/footer/model.ts +40 -5
- package/src/components/market-board/index.tsx +3 -2
- package/src/components/onboarding/desks-step.tsx +12 -4
- package/src/components/onboarding/first-run-workspace.ts +81 -4
- package/src/components/onboarding/onboarding-frame.tsx +2 -1
- package/src/components/onboarding/onboarding-keyboard.ts +8 -5
- package/src/components/onboarding/onboarding-wizard.tsx +54 -23
- package/src/components/onboarding/portfolio-step/positions-panel.tsx +7 -2
- package/src/components/onboarding/run-setup-again.ts +24 -0
- package/src/components/onboarding/use-onboarding-progress.ts +33 -15
- package/src/components/onboarding/use-onboarding-upgrade.ts +2 -6
- package/src/components/onboarding/wizard-model.ts +57 -3
- package/src/components/onboarding/wizard-positions.ts +1 -1
- package/src/components/ui/delayed-mark.tsx +56 -0
- package/src/components/ui/external-link.tsx +3 -6
- package/src/components/ui/icon.tsx +8 -1
- package/src/components/ui/logo-mark.tsx +8 -5
- package/src/components/ui/stat-grid.tsx +263 -19
- package/src/data/config/store/node.ts +11 -5
- package/src/data/config/store/normalize.ts +16 -3
- package/src/data/profile-permissions.ts +47 -0
- package/src/data/resource-store.ts +34 -31
- package/src/data/sqlite/access.ts +19 -8
- package/src/data/sqlite/checkpointer.ts +95 -8
- package/src/data/sqlite/database.ts +40 -7
- package/src/docs/snapshot.json +191 -78
- package/src/i18n/es.ts +18 -2
- package/src/i18n/ja.ts +18 -2
- package/src/i18n/ko.ts +18 -2
- package/src/i18n/zh-cn.ts +18 -2
- package/src/i18n/zh-tw.ts +18 -2
- package/src/layout/desk-keys.ts +4 -1
- package/src/layout/desks.ts +38 -5
- package/src/layout-marketplace/gallery-desktop.tsx +45 -16
- package/src/market-data/batched-reads.ts +16 -0
- package/src/market-data/coordinator/auxiliary.ts +4 -2
- package/src/market-data/coordinator/index.ts +11 -2
- package/src/market-data/futures-board.ts +1 -1
- package/src/market-data/futures-contract.ts +3 -1
- package/src/market-data/market/index-level.ts +6 -4
- package/src/market-data/published-apac-sessions.ts +6 -0
- package/src/news/aggregator.ts +7 -4
- package/src/news/news-model.ts +11 -0
- package/src/news/story-id.ts +22 -0
- package/src/news/ticker-symbols.ts +17 -1
- package/src/notifications/app-notifier.ts +35 -14
- package/src/plugins/builtin/account-management/form-components.tsx +1 -1
- package/src/plugins/builtin/account-management/index.tsx +2 -3
- package/src/plugins/builtin/account-management/model.ts +1 -1
- package/src/plugins/builtin/alerts/cli-forms.ts +15 -1
- package/src/plugins/builtin/alerts/events-pane.tsx +7 -5
- package/src/plugins/builtin/alerts/events.ts +10 -2
- package/src/plugins/builtin/alerts/index.tsx +5 -5
- package/src/plugins/builtin/alerts/research-builder.ts +5 -1
- package/src/plugins/builtin/alerts/research-rules.ts +18 -0
- package/src/plugins/builtin/alerts/targets.ts +4 -1
- package/src/plugins/builtin/attention/headless.ts +1 -1
- package/src/plugins/builtin/attention/index.tsx +2 -4
- package/src/plugins/builtin/attention/listing.ts +1 -1
- package/src/plugins/builtin/attention/series.ts +1 -1
- package/src/plugins/builtin/awards/index.tsx +1 -2
- package/src/plugins/builtin/backtest/client.ts +1 -0
- package/src/plugins/builtin/backtest/index.tsx +1 -2
- package/src/plugins/builtin/backtest/rules.ts +3 -1
- package/src/plugins/builtin/backtest/window.ts +8 -7
- package/src/plugins/builtin/broker-manager/detail.tsx +16 -3
- package/src/plugins/builtin/broker-manager/index.tsx +1 -1
- package/src/plugins/builtin/buildout/cells.tsx +5 -0
- package/src/plugins/builtin/buildout/company/flow.tsx +367 -0
- package/src/plugins/builtin/buildout/company/id.ts +2 -0
- package/src/plugins/builtin/buildout/company/model.ts +247 -0
- package/src/plugins/builtin/buildout/company/pane.tsx +317 -0
- package/src/plugins/builtin/buildout/data-runtime.ts +31 -10
- package/src/plugins/builtin/buildout/facilities.ts +309 -0
- package/src/plugins/builtin/buildout/format.ts +9 -0
- package/src/plugins/builtin/buildout/index.tsx +51 -5
- package/src/plugins/builtin/buildout/model/index.ts +62 -10
- package/src/plugins/builtin/buildout/model/normalizers.ts +5 -0
- package/src/plugins/builtin/buildout/model/types.ts +11 -2
- package/src/plugins/builtin/buildout/pane/index.tsx +91 -20
- package/src/plugins/builtin/buildout/pane/status.tsx +1 -1
- package/src/plugins/builtin/buildout/pane/themes.tsx +110 -0
- package/src/plugins/builtin/buildout/table-model.ts +26 -2
- package/src/plugins/builtin/builtin-plugin-meta.ts +16 -0
- package/src/plugins/builtin/cds/headless.ts +10 -2
- package/src/plugins/builtin/cds/model.ts +7 -3
- package/src/plugins/builtin/central-bank-rates/index.tsx +1 -2
- package/src/plugins/builtin/central-bank-rates/pane.tsx +2 -1
- package/src/plugins/builtin/changelog/index.tsx +3 -2
- package/src/plugins/builtin/chart-composer/headless-schema.ts +7 -2
- package/src/plugins/builtin/chart-composer/headless.ts +88 -21
- package/src/plugins/builtin/chart-composer/index.tsx +2 -3
- package/src/plugins/builtin/chart-composer/pane.tsx +26 -2
- package/src/plugins/builtin/chart-composer/series-expression.ts +3 -2
- package/src/plugins/builtin/chart-composer/studies.ts +1 -1
- package/src/plugins/builtin/chat/controller/index.ts +1 -1
- package/src/plugins/builtin/chat/controller/messages.ts +15 -4
- package/src/plugins/builtin/chat/ghost-user.ts +8 -0
- package/src/plugins/builtin/chat/index.tsx +5 -5
- package/src/plugins/builtin/clinical-trials/index.tsx +1 -2
- package/src/plugins/builtin/cloud/company-picker.tsx +1 -1
- package/src/plugins/builtin/cloud/index.tsx +1 -2
- package/src/plugins/builtin/cloud/plugin.tsx +6 -4
- package/src/plugins/builtin/cloud/team/module.tsx +1 -1
- package/src/plugins/builtin/cloud/thesis/module.tsx +1 -1
- package/src/plugins/builtin/cloud/trial-offer-status-widget.tsx +24 -1
- package/src/plugins/builtin/cloud/upgrade-status-widget.tsx +39 -15
- package/src/plugins/builtin/comment-letters/index.tsx +1 -2
- package/src/plugins/builtin/commodity-balances/index.tsx +3 -3
- package/src/plugins/builtin/commodity-balances/pane.tsx +2 -2
- package/src/plugins/builtin/congress-trades/aggregates.ts +13 -2
- package/src/plugins/builtin/congress-trades/detail.tsx +20 -4
- package/src/plugins/builtin/congress-trades/headless.ts +2 -0
- package/src/plugins/builtin/congress-trades/model.ts +92 -64
- package/src/plugins/builtin/congress-trades/table.tsx +14 -2
- package/src/plugins/builtin/connections/index.ts +2 -3
- package/src/plugins/builtin/cot/index.tsx +1 -2
- package/src/plugins/builtin/cpi/index.tsx +1 -2
- package/src/plugins/builtin/credit-boards/cdx-pane.tsx +2 -1
- package/src/plugins/builtin/credit-boards/client.ts +7 -2
- package/src/plugins/builtin/credit-boards/headless.ts +25 -12
- package/src/plugins/builtin/credit-boards/model.ts +29 -0
- package/src/plugins/builtin/credit-boards/sovr-pane.tsx +9 -4
- package/src/plugins/builtin/crypto-board/bitcoin-network.ts +143 -0
- package/src/plugins/builtin/crypto-board/headless.ts +4 -3
- package/src/plugins/builtin/crypto-board/index.tsx +4 -2
- package/src/plugins/builtin/crypto-board/series.ts +2 -0
- package/src/plugins/builtin/crypto-etf-flows/client.ts +9 -2
- package/src/plugins/builtin/crypto-etf-flows/headless.ts +61 -6
- package/src/plugins/builtin/crypto-etf-flows/index.tsx +1 -2
- package/src/plugins/builtin/crypto-etf-flows/model.ts +14 -1
- package/src/plugins/builtin/crypto-etf-flows/pane.tsx +8 -5
- package/src/plugins/builtin/debt-maturities/headless.ts +4 -3
- package/src/plugins/builtin/debt-maturities/model.ts +17 -1
- package/src/plugins/builtin/debt-maturities/pane.tsx +18 -4
- package/src/plugins/builtin/debug/index.tsx +1 -1
- package/src/plugins/builtin/dividend-yield/client.ts +32 -2
- package/src/plugins/builtin/dividend-yield/headless.ts +58 -33
- package/src/plugins/builtin/dividend-yield/index.tsx +37 -2
- package/src/plugins/builtin/dividend-yield/pane.tsx +32 -13
- package/src/plugins/builtin/dividend-yield/ranking-reads.ts +73 -0
- package/src/plugins/builtin/dividend-yield/ranking-view.tsx +163 -0
- package/src/plugins/builtin/dividend-yield/ranking.ts +1 -1
- package/src/plugins/builtin/dividend-yield/view.ts +21 -0
- package/src/plugins/builtin/docs/index.tsx +2 -3
- package/src/plugins/builtin/doe/headless.ts +16 -3
- package/src/plugins/builtin/doe/index.tsx +5 -4
- package/src/plugins/builtin/earnings/board.tsx +2 -1
- package/src/plugins/builtin/earnings/history.tsx +2 -1
- package/src/plugins/builtin/earnings-ripple/client.ts +32 -7
- package/src/plugins/builtin/earnings-ripple/index.tsx +1 -2
- package/src/plugins/builtin/econ/calendar-model.ts +29 -6
- package/src/plugins/builtin/econ-statistics/index.tsx +1 -2
- package/src/plugins/builtin/equity-screener/client.ts +1 -1
- package/src/plugins/builtin/equity-screener/headless.ts +1 -0
- package/src/plugins/builtin/equity-screener/ideas.ts +30 -1
- package/src/plugins/builtin/equity-screener/index.tsx +1 -2
- package/src/plugins/builtin/equity-screener/model.ts +28 -4
- package/src/plugins/builtin/equity-screener/pane.tsx +5 -0
- package/src/plugins/builtin/equity-screener/screen-check.ts +23 -1
- package/src/plugins/builtin/estimate-revisions/index.tsx +1 -2
- package/src/plugins/builtin/exposure/holdings.ts +35 -13
- package/src/plugins/builtin/exposure/index.tsx +1 -2
- package/src/plugins/builtin/fear-greed/cli.ts +44 -0
- package/src/plugins/builtin/fear-greed/index.tsx +5 -53
- package/src/plugins/builtin/fear-greed/pane.tsx +2 -1
- package/src/plugins/builtin/fixed-income/index.tsx +1 -2
- package/src/plugins/builtin/futures/board-reads.ts +25 -0
- package/src/plugins/builtin/futures/coalesced-bump.ts +44 -0
- package/src/plugins/builtin/futures/index.tsx +15 -0
- package/src/plugins/builtin/futures/model.ts +14 -0
- package/src/plugins/builtin/futures/use-board-terms.ts +22 -15
- package/src/plugins/builtin/futures/use-front-returns.ts +20 -14
- package/src/plugins/builtin/futures-curve/headless.ts +6 -1
- package/src/plugins/builtin/futures-curve/index.tsx +1 -2
- package/src/plugins/builtin/fx-matrix/index.tsx +2 -2
- package/src/plugins/builtin/gpu/board.tsx +51 -12
- package/src/plugins/builtin/gpu/client.ts +15 -2
- package/src/plugins/builtin/gpu/equities.tsx +5 -2
- package/src/plugins/builtin/gpu/headless.ts +14 -2
- package/src/plugins/builtin/gpu/index.tsx +1 -2
- package/src/plugins/builtin/gpu/model.ts +20 -2
- package/src/plugins/builtin/gpu/pane.tsx +1 -1
- package/src/plugins/builtin/help/index.tsx +1 -1
- package/src/plugins/builtin/holders/index-holders.ts +24 -12
- package/src/plugins/builtin/holders/index.tsx +2 -3
- package/src/plugins/builtin/ipo-calendar/index.tsx +1 -2
- package/src/plugins/builtin/iv-history/index.tsx +1 -2
- package/src/plugins/builtin/jodi/index.tsx +1 -2
- package/src/plugins/builtin/kelly-sizer/index.tsx +1 -2
- package/src/plugins/builtin/layout-manager/index.tsx +9 -8
- package/src/plugins/builtin/macro-day/pane.tsx +4 -2
- package/src/plugins/builtin/market-halts/index.tsx +1 -2
- package/src/plugins/builtin/market-heatmap/index.tsx +11 -2
- package/src/plugins/builtin/market-movers/index.tsx +7 -1
- package/src/plugins/builtin/market-movers/session-body.tsx +4 -1
- package/src/plugins/builtin/market-valuation/index.tsx +1 -2
- package/src/plugins/builtin/members/index.tsx +1 -2
- package/src/plugins/builtin/money-markets/index.tsx +1 -2
- package/src/plugins/builtin/money-markets/pane.tsx +2 -1
- package/src/plugins/builtin/news/headless.ts +7 -0
- package/src/plugins/builtin/news/wire/index.tsx +1 -1
- package/src/plugins/builtin/news/wire/news/pop-out.tsx +9 -3
- package/src/plugins/builtin/notes/index.tsx +3 -6
- package/src/plugins/builtin/openfda/index.tsx +1 -2
- package/src/plugins/builtin/options/view.tsx +6 -5
- package/src/plugins/builtin/options-calculator/index.tsx +1 -2
- package/src/plugins/builtin/options-positioning/index.tsx +1 -2
- package/src/plugins/builtin/options-scenario/index.tsx +2 -4
- package/src/plugins/builtin/perps/index.tsx +1 -2
- package/src/plugins/builtin/plugin-marketplace/index.tsx +2 -3
- package/src/plugins/builtin/plugin-marketplace/pane.tsx +2 -1
- package/src/plugins/builtin/plugin-module.ts +16 -2
- package/src/plugins/builtin/portfolio-list/cli/render.ts +53 -3
- package/src/plugins/builtin/portfolio-list/index.tsx +1 -2
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +11 -0
- package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +2 -2
- package/src/plugins/builtin/power/index.tsx +1 -2
- package/src/plugins/builtin/rate-path/index.tsx +1 -2
- package/src/plugins/builtin/realized-vol/headless.ts +2 -0
- package/src/plugins/builtin/realized-vol/index.tsx +1 -2
- package/src/plugins/builtin/realized-vol/model.ts +16 -2
- package/src/plugins/builtin/realized-vol/pane.tsx +3 -3
- package/src/plugins/builtin/relative-rotation/index.tsx +1 -2
- package/src/plugins/builtin/research/analyst-headless.ts +33 -6
- package/src/plugins/builtin/research/analyst-model.ts +37 -2
- package/src/plugins/builtin/research/analyst-pane.tsx +25 -5
- package/src/plugins/builtin/research/index.tsx +5 -8
- package/src/plugins/builtin/research-search/index.tsx +1 -2
- package/src/plugins/builtin/revenue-breakdown/headless.ts +22 -8
- package/src/plugins/builtin/revenue-breakdown/model.ts +23 -0
- package/src/plugins/builtin/reverse-dcf/pane.tsx +4 -2
- package/src/plugins/builtin/roadmap/index.tsx +2 -3
- package/src/plugins/builtin/roadmap/pane.tsx +49 -2
- package/src/plugins/builtin/scanner/hilo-model.ts +18 -1
- package/src/plugins/builtin/scanner/hilo-pane.tsx +12 -2
- package/src/plugins/builtin/scanner/live-pane.tsx +7 -4
- package/src/plugins/builtin/sec/filing-content.ts +38 -6
- package/src/plugins/builtin/sec/headless.ts +5 -1
- package/src/plugins/builtin/sec/index.tsx +4 -2
- package/src/plugins/builtin/sec/model.ts +2 -0
- package/src/plugins/builtin/sectors/index.tsx +11 -5
- package/src/plugins/builtin/series-inventory.ts +2 -0
- package/src/plugins/builtin/shared/cloud-resource.ts +60 -0
- package/src/plugins/builtin/shared/cloud-upgrade.ts +24 -1
- package/src/plugins/builtin/shared/forming-bars.ts +29 -0
- package/src/plugins/builtin/shared/fx-rate-freshness.ts +17 -0
- package/src/plugins/builtin/shared/series-detail-chart.tsx +4 -2
- package/src/plugins/builtin/shared/use-quote-board.ts +5 -0
- package/src/plugins/builtin/short-interest/publications-pane.tsx +2 -1
- package/src/plugins/builtin/short-volume/pane.tsx +2 -1
- package/src/plugins/builtin/social-mentions/index.tsx +1 -2
- package/src/plugins/builtin/social-mentions/pane.tsx +2 -1
- package/src/plugins/builtin/supply-chain/client.ts +22 -1
- package/src/plugins/builtin/supply-chain/graph-client.ts +22 -1
- package/src/plugins/builtin/supply-chain/index.tsx +1 -2
- package/src/plugins/builtin/thirteenf/api.ts +116 -13
- package/src/plugins/builtin/thirteenf/data.ts +132 -30
- package/src/plugins/builtin/thirteenf/index.tsx +2 -4
- package/src/plugins/builtin/thirteenf/model.ts +2 -0
- package/src/plugins/builtin/thirteenf/pane.tsx +20 -11
- package/src/plugins/builtin/thirteenf/types.ts +12 -0
- package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +17 -4
- package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +81 -11
- package/src/plugins/builtin/ticker-detail/headless.ts +11 -3
- package/src/plugins/builtin/ticker-detail/index.tsx +5 -10
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +16 -6
- package/src/plugins/builtin/time-sales/index.tsx +1 -2
- package/src/plugins/builtin/time-sales/pane.tsx +3 -1
- package/src/plugins/builtin/trace-bonds/headless.ts +11 -2
- package/src/plugins/builtin/trace-bonds/model.ts +44 -10
- package/src/plugins/builtin/trace-bonds/pane.tsx +12 -7
- package/src/plugins/builtin/treasury-auctions/pane.tsx +2 -2
- package/src/plugins/builtin/vol-surface/client.ts +18 -3
- package/src/plugins/builtin/vol-surface/index.tsx +1 -2
- package/src/plugins/builtin/volatility/index.tsx +1 -2
- package/src/plugins/builtin/world-indices/footer.ts +6 -1
- package/src/plugins/builtin/world-venue-map/client.ts +10 -1
- package/src/plugins/builtin/world-venue-map/index.ts +6 -2
- package/src/plugins/builtin/world-venue-map/layered-pane.tsx +48 -7
- package/src/plugins/builtin/world-venue-map/layers.ts +17 -0
- package/src/plugins/builtin/world-venue-map/local-layers.ts +141 -0
- package/src/plugins/builtin/world-venue-map/map-symbols.ts +18 -0
- package/src/plugins/builtin/world-venue-map/map.tsx +4 -2
- package/src/plugins/builtin/world-venue-map/scope.ts +63 -0
- package/src/plugins/builtin/yield-curve/curves.ts +16 -2
- package/src/plugins/builtin/yield-curve/headless.ts +3 -3
- package/src/plugins/bundle.ts +52 -2
- package/src/plugins/catalog-browser.ts +2 -2
- package/src/plugins/catalog-cli.ts +20 -0
- package/src/plugins/host-link.ts +13 -1
- package/src/plugins/installer.ts +15 -4
- package/src/plugins/loader.ts +43 -11
- package/src/plugins/peer-imports.ts +201 -0
- package/src/plugins/peer-retry.ts +26 -29
- package/src/plugins/plugin-process.ts +128 -0
- package/src/plugins/redirection-guard.ts +45 -0
- package/src/remote/endpoint.ts +16 -3
- package/src/renderers/browser/main.tsx +3 -2
- package/src/renderers/cloudflare/http-proxy.ts +7 -123
- package/src/renderers/dom/desktop/icons.tsx +2 -0
- package/src/renderers/dom/host/image-surface.tsx +46 -21
- package/src/renderers/dom/styles.css +7 -0
- package/src/renderers/dom/toast-host.tsx +2 -0
- package/src/renderers/electrobun/bun/desktop/backend.ts +7 -1
- package/src/renderers/electrobun/bun/desktop/initialization.ts +3 -2
- package/src/renderers/electrobun/bun/desktop/rpc-timing.ts +88 -0
- package/src/renderers/electrobun/bun/desktop/update.ts +20 -4
- package/src/renderers/electrobun/bun/desktop/view-ids.ts +8 -4
- package/src/renderers/electrobun/bun/external-plugins.ts +4 -0
- package/src/renderers/electrobun/bun/window/create.ts +4 -2
- package/src/renderers/electrobun/bun/window/native-timing.ts +48 -0
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +82 -4
- package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +13 -5
- package/src/renderers/electrobun/view/desktop/window/snapshot.ts +3 -0
- package/src/renderers/electrobun/view/main.tsx +7 -2
- package/src/renderers/electrobun/view/remote/asset-data-client.ts +1 -0
- package/src/renderers/opentui/browser-open.ts +10 -4
- package/src/renderers/opentui/image/surface.tsx +1 -1
- package/src/renderers/opentui/start.tsx +12 -6
- package/src/renderers/opentui/toast-host.tsx +2 -1
- package/src/series/registry.ts +18 -0
- package/src/series/standalone.ts +10 -1
- package/src/series/types.ts +7 -0
- package/src/series/validate.ts +11 -2
- package/src/sources/gloomberb-cloud/index.ts +28 -5
- package/src/sources/gloomberb-cloud/news.ts +24 -3
- package/src/sources/gloomberb-cloud/normalizers.ts +17 -2
- package/src/sources/provider-errors.ts +26 -3
- package/src/sources/provider-router/history.ts +5 -0
- package/src/sources/provider-router/index.ts +13 -0
- package/src/sync/core-contributors.ts +32 -0
- package/src/telemetry/attention-counts.ts +64 -6
- package/src/telemetry/attention-setting.ts +33 -0
- package/src/telemetry/crash-reports-node.ts +3 -1
- package/src/telemetry/stall-clocks.ts +93 -0
- package/src/telemetry/stall-reports-node.ts +12 -7
- package/src/telemetry/stall-reports.ts +34 -5
- package/src/test-support/preload.ts +9 -0
- package/src/tickers/company-name.ts +19 -0
- package/src/tickers/listing-fate.ts +14 -3
- package/src/tickers/saved-instrument.ts +17 -0
- package/src/tickers/search/home-listing.ts +13 -2
- package/src/tickers/search/index.ts +4 -1
- package/src/tickers/search/types.ts +6 -1
- package/src/time-series/bar-aggregation.ts +7 -1
- package/src/time-series/base-series.ts +3 -3
- package/src/time-series/chart-bounds.ts +1 -1
- package/src/time-series/chart-data.ts +5 -2
- package/src/time-series/chart-seed.ts +1 -1
- package/src/time-series/coin-session-close.ts +211 -0
- package/src/time-series/live-bars.ts +13 -2
- package/src/time-series/live-quotes.ts +1 -1
- package/src/time-series/official-close.ts +159 -0
- package/src/time-series/price-comparison.ts +55 -6
- package/src/time-series/resolve.ts +12 -3
- package/src/time-series/series-presentation.ts +1 -1
- package/src/time-series/studies/formula.ts +205 -0
- package/src/time-series/studies/indicators.ts +299 -0
- package/src/time-series/studies/leverage.ts +75 -0
- package/src/time-series/studies/pair.ts +138 -0
- package/src/time-series/studies/resolve.ts +333 -0
- package/src/time-series/studies/shared.ts +141 -0
- package/src/time-series/studies/units.ts +243 -0
- package/src/time-series/studies/vwap.ts +274 -0
- package/src/types/config.ts +18 -2
- package/src/types/data-provider.ts +23 -0
- package/src/types/financials.ts +22 -0
- package/src/types/headless.ts +42 -3
- package/src/types/plugin.ts +32 -3
- package/src/ui/host.tsx +11 -0
- package/src/ui/toast.tsx +26 -1
- package/src/utils/ascii-text.ts +140 -0
- package/src/utils/cli-output.ts +91 -18
- package/src/utils/concurrency.ts +24 -0
- package/src/utils/exchanges.ts +6 -0
- package/src/utils/external-url.ts +20 -7
- package/src/utils/futures-generic.ts +4 -4
- package/src/utils/http-proxy-upstream.ts +124 -0
- package/src/utils/main-thread-stall.ts +75 -3
- package/src/utils/perf-marks.ts +36 -2
- package/src/utils/private-files.ts +141 -0
- package/src/utils/public-address.ts +99 -0
- package/src/account/upgrade-personalization.ts +0 -57
- package/src/account/upgrade-tickers.ts +0 -124
- package/src/api-client/upgrade-experiment.ts +0 -91
- package/src/plugins/builtin/cloud/browser.tsx +0 -3
- package/src/renderers/electrobun/launcher/preload.ts +0 -13
- package/src/renderers/electrobun/launcher/windows-emulation.ts +0 -50
- package/src/time-series/studies.ts +0 -1628
|
@@ -257,7 +257,7 @@ export function ChartTableHeader(props: ChartTableHeaderProps) {
|
|
|
257
257
|
return (
|
|
258
258
|
<Box flexDirection="column" flexShrink={0}>
|
|
259
259
|
{query}
|
|
260
|
-
{layout.figureRows ? <StatGrid items={layout.figures} width={width} /> : null}
|
|
260
|
+
{layout.figureRows ? <StatGrid items={layout.figures} width={width} maxLines={layout.figureMaxLines} /> : null}
|
|
261
261
|
{band}
|
|
262
262
|
</Box>
|
|
263
263
|
);
|
|
@@ -31,6 +31,8 @@ const CHART_SHARE = 0.4;
|
|
|
31
31
|
const SHORT_BODY_ROWS = 12;
|
|
32
32
|
/** The figures never take more than this share of the body. */
|
|
33
33
|
const FIGURE_SHARE = 0.25;
|
|
34
|
+
/** The share of the body figures that wrap rather than cut a date may take, beyond FIGURE_SHARE. */
|
|
35
|
+
const WRAPPED_FIGURE_SHARE = 1 / 3;
|
|
34
36
|
|
|
35
37
|
/**
|
|
36
38
|
* The rows a kit table spends outside its body: the header, plus a horizontal
|
|
@@ -70,15 +72,28 @@ export interface ChartTableLayoutInput {
|
|
|
70
72
|
export interface ChartTableLayout {
|
|
71
73
|
figures: StatItem[];
|
|
72
74
|
figureRows: number;
|
|
75
|
+
/** The lines the figures may take, so a whole-row cell too narrow for one line wraps within them (StatGrid's `maxLines`). */
|
|
76
|
+
figureMaxLines: number;
|
|
73
77
|
mode: ChartBandMode;
|
|
74
78
|
chartRows: number;
|
|
75
79
|
}
|
|
76
80
|
|
|
77
|
-
/**
|
|
78
|
-
function
|
|
81
|
+
/** Rows `figures` take within `maxLines` (StatGrid's own count). */
|
|
82
|
+
function figureRows(figures: readonly StatItem[], width: number, maxLines: number): number {
|
|
83
|
+
return statGridRows([...figures], width, undefined, { maxLines });
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* The figures that fit the row budget a line each, dropped from the end, and
|
|
88
|
+
* the lines they may take: a whole-row figure too narrow for one line wraps
|
|
89
|
+
* onto a second rather than cut a date, into rows up to WRAPPED_FIGURE_SHARE
|
|
90
|
+
* of the body, the leading ones first; the rest keep one line, cut. Wrapping
|
|
91
|
+
* never costs a figure that fits a line. A budget of one row wraps none.
|
|
92
|
+
*/
|
|
93
|
+
function fitFigures(figures: readonly StatItem[], width: number, maxRows: number, body: number): { figures: StatItem[]; maxLines: number } {
|
|
79
94
|
const kept = [...figures];
|
|
80
|
-
while (kept.length > 0 &&
|
|
81
|
-
return kept;
|
|
95
|
+
while (kept.length > 0 && figureRows(kept, width, maxRows) > maxRows) kept.pop();
|
|
96
|
+
return { figures: kept, maxLines: maxRows > 1 ? Math.max(maxRows, Math.floor(body * WRAPPED_FIGURE_SHARE)) : maxRows };
|
|
82
97
|
}
|
|
83
98
|
|
|
84
99
|
/**
|
|
@@ -89,7 +104,9 @@ function fitFigures(figures: readonly StatItem[], width: number, maxRows: number
|
|
|
89
104
|
* fewer), so the rows the pane is about never vanish.
|
|
90
105
|
* - The figures take at most a quarter of the body, one row when it is short
|
|
91
106
|
* or when a second row would cost the chart its place, and lose items from
|
|
92
|
-
* the end rather than
|
|
107
|
+
* the end rather than spill; a whole-row figure wraps onto a second line
|
|
108
|
+
* rather than cut its detail, in rows up to a third of the body, never
|
|
109
|
+
* at the cost of a figure that fits a line.
|
|
93
110
|
* - The chart takes 40% of what is left, or everything the table does not
|
|
94
111
|
* need when all its rows fit, so no blank band opens under a short table.
|
|
95
112
|
* - Below a readable chart the band becomes a one-row strip, then nothing.
|
|
@@ -125,11 +142,11 @@ function layoutWithFigureRows(input: ChartTableLayoutInput, body: number, figure
|
|
|
125
142
|
|
|
126
143
|
// A table with no room for a single row after the figures gets the body back.
|
|
127
144
|
const figureBudget = Math.min(figureCap, Math.max(0, body - chrome - Math.min(tableRows, 1)));
|
|
128
|
-
const figures = figureBudget > 0 ? fitFigures(input.figures ?? [], width, figureBudget) : [];
|
|
129
|
-
const
|
|
145
|
+
const { figures, maxLines: figureMaxLines } = figureBudget > 0 ? fitFigures(input.figures ?? [], width, figureBudget, body) : { figures: [], maxLines: 0 };
|
|
146
|
+
const shownRows = figures.length ? figureRows(figures, width, figureMaxLines) : 0;
|
|
130
147
|
|
|
131
|
-
const rest = body -
|
|
132
|
-
const none: ChartTableLayout = { figures, figureRows, mode: "none", chartRows: 0 };
|
|
148
|
+
const rest = body - shownRows;
|
|
149
|
+
const none: ChartTableLayout = { figures, figureRows: shownRows, figureMaxLines, mode: "none", chartRows: 0 };
|
|
133
150
|
if (!input.chart || width < CHART_MIN_WIDTH) return none;
|
|
134
151
|
|
|
135
152
|
const minRows = input.chart.minRows ?? CHART_MIN_ROWS;
|
|
@@ -137,7 +154,7 @@ function layoutWithFigureRows(input: ChartTableLayoutInput, body: number, figure
|
|
|
137
154
|
const maxRows = input.chart.maxRows ?? Number.POSITIVE_INFINITY;
|
|
138
155
|
const room = rest - tableMin;
|
|
139
156
|
const spare = rest - tableFit;
|
|
140
|
-
const full = (rows: number): ChartTableLayout => ({ figures, figureRows, mode: "full", chartRows: Math.min(rows, maxRows) });
|
|
157
|
+
const full = (rows: number): ChartTableLayout => ({ figures, figureRows: shownRows, figureMaxLines, mode: "full", chartRows: Math.min(rows, maxRows) });
|
|
141
158
|
if (room >= minRows) {
|
|
142
159
|
// With every table row in view beside a readable chart, the chart takes
|
|
143
160
|
// exactly the rest; otherwise its 40% share, never below what it draws in.
|
|
@@ -148,7 +165,7 @@ function layoutWithFigureRows(input: ChartTableLayoutInput, body: number, figure
|
|
|
148
165
|
// instead of a strip over a blank band.
|
|
149
166
|
if (spare >= compactRows) return full(spare);
|
|
150
167
|
if (input.chart.strip !== false && room >= 1) {
|
|
151
|
-
return { figures, figureRows, mode: "strip", chartRows: 1 };
|
|
168
|
+
return { figures, figureRows: shownRows, figureMaxLines, mode: "strip", chartRows: 1 };
|
|
152
169
|
}
|
|
153
170
|
return none;
|
|
154
171
|
}
|
|
@@ -32,6 +32,8 @@ interface UseCommandBarActionRuntimeOptions {
|
|
|
32
32
|
dispatch: Dispatch<AppAction>;
|
|
33
33
|
focusedPaneId: string | null;
|
|
34
34
|
onCheckForUpdates?: () => void | Promise<void>;
|
|
35
|
+
/** Settings' Run Setup Again; absent where setup cannot run. */
|
|
36
|
+
onRunSetupAgain?: () => Promise<void>;
|
|
35
37
|
persistConfig: (nextConfig: AppState["config"]) => void;
|
|
36
38
|
pluginRegistry: PluginRegistry;
|
|
37
39
|
pushRoute: (route: CommandBarRoute) => void;
|
|
@@ -57,6 +59,7 @@ export function useCommandBarActionRuntime({
|
|
|
57
59
|
dispatch,
|
|
58
60
|
focusedPaneId,
|
|
59
61
|
onCheckForUpdates,
|
|
62
|
+
onRunSetupAgain,
|
|
60
63
|
persistConfig,
|
|
61
64
|
pluginRegistry,
|
|
62
65
|
pushRoute,
|
|
@@ -222,6 +225,7 @@ export function useCommandBarActionRuntime({
|
|
|
222
225
|
focusTicker,
|
|
223
226
|
notify,
|
|
224
227
|
onCheckForUpdates,
|
|
228
|
+
onRunSetupAgain,
|
|
225
229
|
openBuiltInWorkflow,
|
|
226
230
|
openInlineConfirm,
|
|
227
231
|
openModeRoute,
|
|
@@ -29,6 +29,7 @@ import { parseWindowModeCommandArg } from "../../layout-items";
|
|
|
29
29
|
import type { CommandBarRoute } from "../../workflow/types";
|
|
30
30
|
import { recordFunctionOpen } from "../../../../telemetry/usage-counts";
|
|
31
31
|
import { reportTelemetryConfig } from "../../../../telemetry/live-config";
|
|
32
|
+
import { ATTENTION_OFF_MESSAGE } from "../../../../telemetry/attention-setting";
|
|
32
33
|
import { NIGHTLY_CHANNEL_SUMMARY, withUpdateChannel } from "../../../../updater/channel";
|
|
33
34
|
import { isPrereleaseVersion } from "../../../../utils/semver";
|
|
34
35
|
import { VERSION } from "../../../../version";
|
|
@@ -53,6 +54,8 @@ export function runDirectCommandAction(options: {
|
|
|
53
54
|
getState: () => AppState;
|
|
54
55
|
notify: NotifyFn;
|
|
55
56
|
onCheckForUpdates?: () => void | Promise<void>;
|
|
57
|
+
/** Settings' Run Setup Again; absent where setup cannot run. */
|
|
58
|
+
onRunSetupAgain?: () => Promise<void>;
|
|
56
59
|
openBuiltInWorkflow: (actionId: string) => void;
|
|
57
60
|
openInlineConfirm: OpenInlineConfirm;
|
|
58
61
|
openModeRoute: (screen: "ticker-search" | "layout", initialQuery?: string) => void;
|
|
@@ -78,6 +81,7 @@ export function runDirectCommandAction(options: {
|
|
|
78
81
|
getState,
|
|
79
82
|
notify,
|
|
80
83
|
onCheckForUpdates,
|
|
84
|
+
onRunSetupAgain,
|
|
81
85
|
openBuiltInWorkflow,
|
|
82
86
|
openInlineConfirm,
|
|
83
87
|
openModeRoute,
|
|
@@ -329,47 +333,22 @@ export function runDirectCommandAction(options: {
|
|
|
329
333
|
return;
|
|
330
334
|
}
|
|
331
335
|
case "toggle-crash-reports":
|
|
332
|
-
case "toggle-usage-counts":
|
|
333
|
-
|
|
336
|
+
case "toggle-usage-counts":
|
|
337
|
+
case "toggle-attention-counts": {
|
|
338
|
+
const key = command.id === "toggle-crash-reports" ? "crashReports" : command.id === "toggle-usage-counts" ? "usage" : "attention";
|
|
339
|
+
// All three are on by default: only an explicit false is off.
|
|
334
340
|
const enabled = state.config.telemetry?.[key] === false;
|
|
335
341
|
const nextConfig = { ...state.config, telemetry: { ...state.config.telemetry, [key]: enabled } };
|
|
342
|
+
// Reported before React commits, so turning Attention Counts off drops unsent counts at once.
|
|
336
343
|
reportTelemetryConfig(nextConfig.telemetry);
|
|
337
344
|
dispatch({ type: "SET_CONFIG", config: nextConfig });
|
|
338
345
|
persistConfig(nextConfig);
|
|
339
|
-
notify(
|
|
346
|
+
notify(key === "attention" && !enabled
|
|
347
|
+
? t(ATTENTION_OFF_MESSAGE)
|
|
348
|
+
: `${t(command.label)}: ${t(enabled ? "on" : "off")}`, { type: "success" });
|
|
340
349
|
closeAll({ revertThemePreview: false });
|
|
341
350
|
return;
|
|
342
351
|
}
|
|
343
|
-
case "toggle-attention-counts": {
|
|
344
|
-
const setEnabled = (enabled: boolean) => {
|
|
345
|
-
const current = getState().config;
|
|
346
|
-
const nextConfig = { ...current, telemetry: { ...current.telemetry, attention: enabled } };
|
|
347
|
-
// Clear unsent counts before React commits the settings update.
|
|
348
|
-
reportTelemetryConfig(nextConfig.telemetry);
|
|
349
|
-
dispatch({ type: "SET_CONFIG", config: nextConfig });
|
|
350
|
-
persistConfig(nextConfig);
|
|
351
|
-
notify(`${t(command.label)}: ${t(enabled ? "on" : "off")}`, { type: "success" });
|
|
352
|
-
};
|
|
353
|
-
if (state.config.telemetry?.attention === true) {
|
|
354
|
-
setEnabled(false);
|
|
355
|
-
closeAll({ revertThemePreview: false });
|
|
356
|
-
} else {
|
|
357
|
-
openInlineConfirm({
|
|
358
|
-
confirmId: "enable-attention-counts",
|
|
359
|
-
title: "Share Attention Counts?",
|
|
360
|
-
body: [
|
|
361
|
-
"While signed in with a verified account, share the tickers you open in DES, charts, quotes and options, and add to watchlists.",
|
|
362
|
-
"Gloom uses your account to limit contributions. Published counts are delayed and rounded, and require at least 20 contributors. Your holdings, watchlist names and searches are not included.",
|
|
363
|
-
"This is separate from Usage Counts and is off by default. Turn it off at any time to stop collection and discard unsent counts. Already published anonymous totals cannot be removed.",
|
|
364
|
-
],
|
|
365
|
-
confirmLabel: "Share Counts",
|
|
366
|
-
cancelLabel: "Keep Off",
|
|
367
|
-
tone: "default",
|
|
368
|
-
onConfirm: async () => { setEnabled(true); },
|
|
369
|
-
});
|
|
370
|
-
}
|
|
371
|
-
return;
|
|
372
|
-
}
|
|
373
352
|
case "font-size-increase":
|
|
374
353
|
case "font-size-decrease": {
|
|
375
354
|
const delta = command.id === "font-size-increase" ? 1 : -1;
|
|
@@ -391,6 +370,12 @@ export function runDirectCommandAction(options: {
|
|
|
391
370
|
void onCheckForUpdates?.();
|
|
392
371
|
closeAll({ revertThemePreview: false });
|
|
393
372
|
return;
|
|
373
|
+
case "run-setup-again":
|
|
374
|
+
closeAll({ revertThemePreview: false });
|
|
375
|
+
void onRunSetupAgain?.().catch((error: unknown) => {
|
|
376
|
+
notify(error instanceof Error ? error.message : String(error), { type: "error" });
|
|
377
|
+
});
|
|
378
|
+
return;
|
|
394
379
|
case "release-channel": {
|
|
395
380
|
// The runtime checks again as soon as the channel changes.
|
|
396
381
|
const setChannel = (channel: "stable" | "nightly") => {
|
|
@@ -39,6 +39,8 @@ interface UseCommandBarDirectCommandRuntimeOptions {
|
|
|
39
39
|
focusTicker: (symbol: string, options?: PinTickerOptions) => void;
|
|
40
40
|
notify: (body: string, options?: { type?: "info" | "success" | "error" }) => void;
|
|
41
41
|
onCheckForUpdates?: () => void | Promise<void>;
|
|
42
|
+
/** Settings' Run Setup Again; absent where setup cannot run. */
|
|
43
|
+
onRunSetupAgain?: () => Promise<void>;
|
|
42
44
|
openBuiltInWorkflow: (actionId: string) => void;
|
|
43
45
|
openInlineConfirm: OpenInlineConfirm;
|
|
44
46
|
openModeRoute: (
|
|
@@ -66,6 +68,7 @@ export function useCommandBarDirectCommandRuntime({
|
|
|
66
68
|
focusTicker,
|
|
67
69
|
notify,
|
|
68
70
|
onCheckForUpdates,
|
|
71
|
+
onRunSetupAgain,
|
|
69
72
|
openBuiltInWorkflow,
|
|
70
73
|
openInlineConfirm,
|
|
71
74
|
openModeRoute,
|
|
@@ -136,6 +139,7 @@ export function useCommandBarDirectCommandRuntime({
|
|
|
136
139
|
getState,
|
|
137
140
|
notify,
|
|
138
141
|
onCheckForUpdates,
|
|
142
|
+
onRunSetupAgain,
|
|
139
143
|
openBuiltInWorkflow,
|
|
140
144
|
openInlineConfirm,
|
|
141
145
|
openModeRoute,
|
|
@@ -159,6 +163,7 @@ export function useCommandBarDirectCommandRuntime({
|
|
|
159
163
|
getState,
|
|
160
164
|
notify,
|
|
161
165
|
onCheckForUpdates,
|
|
166
|
+
onRunSetupAgain,
|
|
162
167
|
openBuiltInWorkflow,
|
|
163
168
|
openInlineConfirm,
|
|
164
169
|
openModeRoute,
|
|
@@ -276,7 +276,7 @@ export const commands: Command[] = [
|
|
|
276
276
|
id: "toggle-attention-counts",
|
|
277
277
|
prefix: "",
|
|
278
278
|
label: "Attention Counts",
|
|
279
|
-
description: "
|
|
279
|
+
description: "Turn ticker research counts on or off (on by default)",
|
|
280
280
|
category: "Config",
|
|
281
281
|
},
|
|
282
282
|
|
|
@@ -309,6 +309,15 @@ export const commands: Command[] = [
|
|
|
309
309
|
category: "Config",
|
|
310
310
|
},
|
|
311
311
|
|
|
312
|
+
// Setup, from its first step on what the user has (components/onboarding/run-setup-again.ts)
|
|
313
|
+
{
|
|
314
|
+
id: "run-setup-again",
|
|
315
|
+
prefix: "",
|
|
316
|
+
label: "Run Setup Again",
|
|
317
|
+
description: "Rebuild Home and setup's desk tabs; your other layouts stay",
|
|
318
|
+
category: "Config",
|
|
319
|
+
},
|
|
320
|
+
|
|
312
321
|
// Import/Export
|
|
313
322
|
{
|
|
314
323
|
id: "export-config",
|
|
@@ -109,6 +109,9 @@ export function createRootCommandItemBuilder({
|
|
|
109
109
|
if (state.updateProgress?.phase === "ready") return "Update ready, restart to apply";
|
|
110
110
|
if (state.updateProgress?.phase === "error") return failedUpdateLabel(state.updateProgress);
|
|
111
111
|
return command.label;
|
|
112
|
+
// Unlike its neighbours it started out off, so the row says what the default is now.
|
|
113
|
+
case "toggle-attention-counts":
|
|
114
|
+
return `${command.label} (on by default)`;
|
|
112
115
|
default:
|
|
113
116
|
return command.label;
|
|
114
117
|
}
|
|
@@ -175,9 +178,9 @@ export function createRootCommandItemBuilder({
|
|
|
175
178
|
case "toggle-usage-counts":
|
|
176
179
|
return state.config.telemetry?.usage === false ? "Currently off" : "Currently on";
|
|
177
180
|
case "toggle-attention-counts":
|
|
178
|
-
return state.config.telemetry?.attention ===
|
|
179
|
-
? "Currently on
|
|
180
|
-
: "Currently
|
|
181
|
+
return state.config.telemetry?.attention === false
|
|
182
|
+
? "Currently off. Signed in, this turns it off on your other devices too"
|
|
183
|
+
: "Currently on: tickers you open go to Gloom, published only as hourly totals of 20+ people";
|
|
181
184
|
case "release-channel":
|
|
182
185
|
if (resolveUpdateChannel(state.config) === "nightly") return `Currently nightly: ${NIGHTLY_CHANNEL_SUMMARY}`;
|
|
183
186
|
return isPrereleaseVersion(VERSION)
|
|
@@ -201,7 +204,7 @@ export function createRootCommandItemBuilder({
|
|
|
201
204
|
case "toggle-usage-counts":
|
|
202
205
|
return state.config.telemetry?.usage === false ? "off" : "on";
|
|
203
206
|
case "toggle-attention-counts":
|
|
204
|
-
return state.config.telemetry?.attention ===
|
|
207
|
+
return state.config.telemetry?.attention === false ? "off" : "on";
|
|
205
208
|
case "release-channel":
|
|
206
209
|
return resolveUpdateChannel(state.config);
|
|
207
210
|
default:
|
|
@@ -223,6 +226,8 @@ export function createRootCommandItemBuilder({
|
|
|
223
226
|
return "update";
|
|
224
227
|
case "release-channel":
|
|
225
228
|
return "nightly stable beta prerelease update updates channel";
|
|
229
|
+
case "run-setup-again":
|
|
230
|
+
return "settings onboarding wizard guide first run start over desks holdings";
|
|
226
231
|
default:
|
|
227
232
|
return "";
|
|
228
233
|
}
|
|
@@ -20,6 +20,21 @@ import { buildRootShortcutFeedback } from "./shortcut-feedback";
|
|
|
20
20
|
import type { ShortcutIntent } from "./shortcuts";
|
|
21
21
|
import { clampIndex } from "../../../../utils/math";
|
|
22
22
|
|
|
23
|
+
/** Written the way a symbol is: up to five letters and a share class (AAPL, nvda, BRK.B). */
|
|
24
|
+
const SYMBOL_SHAPED_QUERY = /^[A-Za-z]{1,5}(?:[.\-/][A-Za-z]{1,2})?$/;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Text that asks for a symbol rather than a local row: symbol-shaped, and in
|
|
28
|
+
* capitals or in no row's name. `nvda` matches Exposure only through its
|
|
29
|
+
* example input; `upd` is in Check for Updates.
|
|
30
|
+
*/
|
|
31
|
+
function readsAsSymbol(text: string, rows: readonly ResultItem[]): boolean {
|
|
32
|
+
if (!SYMBOL_SHAPED_QUERY.test(text)) return false;
|
|
33
|
+
if (text === text.toUpperCase()) return true;
|
|
34
|
+
const wanted = text.toLowerCase();
|
|
35
|
+
return !rows.some((row) => isDefaultSelectable(row) && row.label.toLowerCase().includes(wanted));
|
|
36
|
+
}
|
|
37
|
+
|
|
23
38
|
interface UseCommandBarRootRuntimeOptions {
|
|
24
39
|
activeCollectionId: string | null;
|
|
25
40
|
activePortfolio?: AppState["config"]["portfolios"][number];
|
|
@@ -317,6 +332,13 @@ export function useCommandBarRootRuntime({
|
|
|
317
332
|
writeTickerSearchCache,
|
|
318
333
|
});
|
|
319
334
|
const rootSearching = tickerSearching || providerSearching;
|
|
335
|
+
// A symbol whose search has not answered: the rows on screen are what the
|
|
336
|
+
// letters match locally (a pane whose example names AAPL), not the symbol,
|
|
337
|
+
// so none of them is highlighted and Enter waits for the answer, as it would
|
|
338
|
+
// get had the symbol been typed slowly. Lower case found in a row's name
|
|
339
|
+
// (`upd`, `list`) is that row and runs at once.
|
|
340
|
+
const rootSymbolAnswerPending = !rootResultsCurrent && rootPlainTickerSearchArg !== null
|
|
341
|
+
&& (rootTickerReading !== null || rootListingChoice !== null || readsAsSymbol(rootPlainTickerSearchArg, orderedRootResults));
|
|
320
342
|
|
|
321
343
|
useLayoutEffect(() => {
|
|
322
344
|
if (currentRoute) return;
|
|
@@ -353,7 +375,7 @@ export function useCommandBarRootRuntime({
|
|
|
353
375
|
// them is the answer and none is selected: Enter must not take one of
|
|
354
376
|
// them for the ticker still being searched.
|
|
355
377
|
const defaultIdx = orderedRootResults.findIndex(isDefaultSelectable);
|
|
356
|
-
if (defaultIdx < 0) return -1;
|
|
378
|
+
if (defaultIdx < 0 || rootSymbolAnswerPending) return -1;
|
|
357
379
|
const selected = clampIndex(Math.max(rootResultModel.initialIdx, defaultIdx), resultIds.length);
|
|
358
380
|
pinnedRootRowRef.current = rootResultsCurrent && resultIds[selected]
|
|
359
381
|
? { id: resultIds[selected]!, answer: activeRootProviderResultsKey }
|
|
@@ -370,6 +392,7 @@ export function useCommandBarRootRuntime({
|
|
|
370
392
|
rootQuery,
|
|
371
393
|
rootResultModel.initialIdx,
|
|
372
394
|
rootSelectionNavigatedRef,
|
|
395
|
+
rootSymbolAnswerPending,
|
|
373
396
|
setRootHoveredIdx,
|
|
374
397
|
setRootSelectedIdx,
|
|
375
398
|
]);
|
|
@@ -44,6 +44,8 @@ interface CommandBarProps {
|
|
|
44
44
|
pluginRegistry: PluginRegistry;
|
|
45
45
|
quitApp: () => void;
|
|
46
46
|
onCheckForUpdates?: () => void | Promise<void>;
|
|
47
|
+
/** Settings' Run Setup Again; without it (the browser, or setup already showing) the command is left out. */
|
|
48
|
+
onRunSetupAgain?: () => Promise<void>;
|
|
47
49
|
onNativeOccluderChange?: (rect: LayoutBounds | null) => void;
|
|
48
50
|
}
|
|
49
51
|
|
|
@@ -53,6 +55,7 @@ export function CommandBar({
|
|
|
53
55
|
pluginRegistry,
|
|
54
56
|
quitApp,
|
|
55
57
|
onCheckForUpdates,
|
|
58
|
+
onRunSetupAgain,
|
|
56
59
|
onNativeOccluderChange,
|
|
57
60
|
}: CommandBarProps) {
|
|
58
61
|
const {
|
|
@@ -80,9 +83,11 @@ export function CommandBar({
|
|
|
80
83
|
visibleListStateRef,
|
|
81
84
|
} = useCommandBarEnvironment();
|
|
82
85
|
// Without an updater (the web terminal) neither checking nor a channel means anything.
|
|
83
|
-
const availableCommands = useMemo(() =>
|
|
84
|
-
|
|
85
|
-
|
|
86
|
+
const availableCommands = useMemo(() => allAvailableCommands.filter((command) => {
|
|
87
|
+
if (command.id === "check-for-updates" || command.id === "release-channel") return !!onCheckForUpdates;
|
|
88
|
+
if (command.id === "run-setup-again") return !!onRunSetupAgain;
|
|
89
|
+
return true;
|
|
90
|
+
}), [allAvailableCommands, onCheckForUpdates, onRunSetupAgain]);
|
|
86
91
|
const {
|
|
87
92
|
applyThemePreview,
|
|
88
93
|
clearThemePreview,
|
|
@@ -200,6 +205,7 @@ export function CommandBar({
|
|
|
200
205
|
dispatch,
|
|
201
206
|
focusedPaneId: state.focusedPaneId,
|
|
202
207
|
onCheckForUpdates,
|
|
208
|
+
onRunSetupAgain,
|
|
203
209
|
persistConfig,
|
|
204
210
|
pluginRegistry,
|
|
205
211
|
pushRoute,
|
|
@@ -84,6 +84,7 @@ export function CompanyLogo({
|
|
|
84
84
|
alignItems="center"
|
|
85
85
|
justifyContent="center"
|
|
86
86
|
objectFit="contain"
|
|
87
|
+
fallbackWhileLoading
|
|
87
88
|
style={{
|
|
88
89
|
width: cellWidthPx * width,
|
|
89
90
|
height: cellHeightPx * height,
|
|
@@ -91,7 +92,7 @@ export function CompanyLogo({
|
|
|
91
92
|
...style,
|
|
92
93
|
}}
|
|
93
94
|
>
|
|
94
|
-
{/* Without a logo the initial fills the same tile, so the header keeps its shape. */}
|
|
95
|
+
{/* Without a logo, or until it loads, the initial fills the same tile, so the header keeps its shape. */}
|
|
95
96
|
<Box width="100%" height="100%" bg={colors.border} alignItems="center" justifyContent="center">
|
|
96
97
|
<Text
|
|
97
98
|
fg={colors.text}
|
|
@@ -36,6 +36,7 @@ import { resolveHeaderPromptGeometry } from "./shell/chrome";
|
|
|
36
36
|
import { useWindowFullscreen } from "./window-fullscreen";
|
|
37
37
|
import { WindowControls, WINDOWS_CONTROL_GROUP_WIDTH_PX } from "./window-controls";
|
|
38
38
|
import { Button, terminalButtonColumns } from "../ui/button";
|
|
39
|
+
import { DelayedMark, delayedMarkWidth } from "../ui/delayed-mark";
|
|
39
40
|
|
|
40
41
|
const UPDATE_NOTICE_DURATION_MS = 5_000;
|
|
41
42
|
/** Kept clear after the terminal update status, so its last character never touches the Help pill. */
|
|
@@ -768,7 +769,10 @@ function HeaderMarketSummary({ nativePaneChrome, width }: { nativePaneChrome: bo
|
|
|
768
769
|
available: width,
|
|
769
770
|
baseCurrencyWidth: displayWidth(summary.baseCurrencyLabel) + 1,
|
|
770
771
|
countdownWidth: summary.marketLabel.length - summary.marketLabelShort.length,
|
|
771
|
-
|
|
772
|
+
// A delayed SPY keeps its mark: the two fit, or give way, together. Once the
|
|
773
|
+
// rest of the cluster is gone, it gives up its move rather than give way.
|
|
774
|
+
spyWidth: summary.spyText.length + 1 + (summary.spyDelayMinutes != null ? delayedMarkWidth(summary.spyDelayMinutes, nativePaneChrome) + 1 : 0),
|
|
775
|
+
spyMoveWidth: summary.spyDelayMinutes != null ? summary.spyText.length - summary.spyPriceText.length : 0,
|
|
772
776
|
stateWidth: summary.marketLabelShort ? summary.marketLabelShort.length + 1 : 0,
|
|
773
777
|
});
|
|
774
778
|
const marketLabel = fit.showCountdown ? summary.marketLabel : summary.marketLabelShort;
|
|
@@ -783,8 +787,9 @@ function HeaderMarketSummary({ nativePaneChrome, width }: { nativePaneChrome: bo
|
|
|
783
787
|
</Box>
|
|
784
788
|
) : null}
|
|
785
789
|
{fit.showSpy ? (
|
|
786
|
-
<Box paddingRight={1} flexShrink={0} data-gloom-role="header-market">
|
|
787
|
-
<Text fg={summary.spyColor}>{summary.spyText}</Text>
|
|
790
|
+
<Box paddingRight={1} flexShrink={0} flexDirection="row" alignItems="center" gap={1} data-gloom-role="header-market">
|
|
791
|
+
<Text fg={summary.spyColor}>{fit.showSpyMove ? summary.spyText : summary.spyPriceText}</Text>
|
|
792
|
+
{summary.spyDelayMinutes != null ? <DelayedMark minutes={summary.spyDelayMinutes} /> : null}
|
|
788
793
|
</Box>
|
|
789
794
|
) : null}
|
|
790
795
|
{fit.showBaseCurrency ? (
|
|
@@ -12,6 +12,7 @@ import { formatPercentRaw } from "../../utils/format";
|
|
|
12
12
|
import { formatMarketPriceWithCurrency, liveQuoteFormatOptions } from "../../market-data/market/format";
|
|
13
13
|
import { getSessionMoveDisplay, marketStateColor, marketStateCountdown, marketStateLabel } from "../../market-data/market/status";
|
|
14
14
|
import type { Quote } from "../../types/financials";
|
|
15
|
+
import { useFreeQuoteDelay } from "../../api-client/plan-access";
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* SPY rides the shared feed. The snapshot poll only runs while the feed has
|
|
@@ -42,6 +43,10 @@ export interface MarketSummary {
|
|
|
42
43
|
marketLabelShort: string;
|
|
43
44
|
spyColor: string;
|
|
44
45
|
spyText: string;
|
|
46
|
+
/** `spyText` without its move (`SPY $762.43`), for a delayed SPY in a header too narrow for both and the mark. */
|
|
47
|
+
spyPriceText: string;
|
|
48
|
+
/** Minutes SPY's price is late for this account (signed out or free), drawn as the delayed mark beside it; null when live. */
|
|
49
|
+
spyDelayMinutes: number | null;
|
|
45
50
|
}
|
|
46
51
|
|
|
47
52
|
export interface MarketSummaryFit {
|
|
@@ -49,6 +54,8 @@ export interface MarketSummaryFit {
|
|
|
49
54
|
showCountdown: boolean;
|
|
50
55
|
showState: boolean;
|
|
51
56
|
showSpy: boolean;
|
|
57
|
+
/** SPY keeps its move; false when it gave the move up to stay (`spyMoveWidth`). */
|
|
58
|
+
showSpyMove: boolean;
|
|
52
59
|
}
|
|
53
60
|
|
|
54
61
|
/**
|
|
@@ -57,12 +64,16 @@ export interface MarketSummaryFit {
|
|
|
57
64
|
* base currency, then the countdown suffix that widens the label. A narrowing
|
|
58
65
|
* header therefore sheds the countdown, then the currency, then the state, and
|
|
59
66
|
* keeps SPY longest. `countdownWidth` is what the suffix adds to the label.
|
|
67
|
+
* `spyMoveWidth` is what SPY's move adds to `spyWidth`, for a SPY that gives
|
|
68
|
+
* its move up before it gives way: a delayed SPY, whose mark makes it wider,
|
|
69
|
+
* so a narrow header still shows it and says it is late.
|
|
60
70
|
*/
|
|
61
71
|
export function resolveMarketSummaryFit(options: {
|
|
62
72
|
available: number;
|
|
63
73
|
baseCurrencyWidth: number;
|
|
64
74
|
countdownWidth: number;
|
|
65
75
|
spyWidth: number;
|
|
76
|
+
spyMoveWidth?: number;
|
|
66
77
|
stateWidth: number;
|
|
67
78
|
}): MarketSummaryFit {
|
|
68
79
|
let remaining = options.available;
|
|
@@ -71,11 +82,13 @@ export function resolveMarketSummaryFit(options: {
|
|
|
71
82
|
remaining -= width;
|
|
72
83
|
return true;
|
|
73
84
|
};
|
|
74
|
-
const
|
|
85
|
+
const spyMoveWidth = options.spyMoveWidth ?? 0;
|
|
86
|
+
const showSpyMove = take(options.spyWidth);
|
|
87
|
+
const showSpy = showSpyMove || (spyMoveWidth > 0 && take(options.spyWidth - spyMoveWidth));
|
|
75
88
|
const showState = take(options.stateWidth);
|
|
76
89
|
const showBaseCurrency = take(options.baseCurrencyWidth);
|
|
77
90
|
const showCountdown = showState && take(options.countdownWidth);
|
|
78
|
-
return { showBaseCurrency, showCountdown, showState, showSpy };
|
|
91
|
+
return { showBaseCurrency, showCountdown, showState, showSpy, showSpyMove: showSpy && showSpyMove };
|
|
79
92
|
}
|
|
80
93
|
|
|
81
94
|
/**
|
|
@@ -87,15 +100,17 @@ export function resolveMarketSummaryFit(options: {
|
|
|
87
100
|
* The price carries its currency's sign ($), so the base currency label
|
|
88
101
|
* after it is never read as its unit.
|
|
89
102
|
*/
|
|
90
|
-
export function spySummary(quote: Quote | null | undefined, colors: ThemeColors): Pick<MarketSummary, "spyColor" | "spyText"> {
|
|
103
|
+
export function spySummary(quote: Quote | null | undefined, colors: ThemeColors): Pick<MarketSummary, "spyColor" | "spyPriceText" | "spyText"> {
|
|
91
104
|
const display = getSessionMoveDisplay(quote);
|
|
92
105
|
// Fixed decimals and a percent slot as wide as "+0.53%", so a streamed tick
|
|
93
106
|
// never slides the market-state label or re-fits the cluster.
|
|
107
|
+
const spyPriceText = display
|
|
108
|
+
? `SPY ${formatMarketPriceWithCurrency(display.price, quote?.currency || "USD", liveQuoteFormatOptions(quote, quote?.currency, "ETF"))}`
|
|
109
|
+
: "SPY —";
|
|
94
110
|
return {
|
|
95
111
|
spyColor: display?.change != null ? priceColor(display.change, colors) : colors.textDim,
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
: "SPY —",
|
|
112
|
+
spyPriceText,
|
|
113
|
+
spyText: display ? `${spyPriceText} ${formatPercentRaw(display.changePercent).padStart(6)}` : spyPriceText,
|
|
99
114
|
};
|
|
100
115
|
}
|
|
101
116
|
|
|
@@ -135,7 +150,8 @@ export function useMarketSummary(): MarketSummary {
|
|
|
135
150
|
return () => { clearInterval(id); };
|
|
136
151
|
}, [appActive]);
|
|
137
152
|
|
|
138
|
-
const { spyColor, spyText } = spySummary(spyQuote, colors);
|
|
153
|
+
const { spyColor, spyPriceText, spyText } = spySummary(spyQuote, colors);
|
|
154
|
+
const spyDelayMinutes = useFreeQuoteDelay(spyQuote);
|
|
139
155
|
|
|
140
156
|
const mktCountdown = mktState ? marketStateCountdown(mktState, now) : null;
|
|
141
157
|
const marketLabelShort = mktState ? t(marketStateLabel(mktState)) : "";
|
|
@@ -149,6 +165,8 @@ export function useMarketSummary(): MarketSummary {
|
|
|
149
165
|
marketLabel,
|
|
150
166
|
marketLabelShort,
|
|
151
167
|
spyColor,
|
|
168
|
+
spyPriceText,
|
|
152
169
|
spyText,
|
|
170
|
+
spyDelayMinutes,
|
|
153
171
|
};
|
|
154
172
|
}
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
} from "./model";
|
|
25
25
|
|
|
26
26
|
export {
|
|
27
|
+
ageFooterSegment,
|
|
27
28
|
companyDataFooterSegment,
|
|
28
29
|
datesPaneData,
|
|
29
30
|
DELAYED_SEGMENT,
|
|
@@ -80,10 +81,12 @@ function terminalSegmentKey(segment: PaneFooterSegment, focused: boolean): strin
|
|
|
80
81
|
: "";
|
|
81
82
|
}
|
|
82
83
|
|
|
83
|
-
/** Columns an icon segment keeps when hints crowd the footer. */
|
|
84
|
+
/** Columns an icon segment keeps when hints crowd the footer: the icon, and on the desktop its `iconText` after it. */
|
|
84
85
|
function iconSegmentReserve(segment: PaneFooterSegment, focused: boolean, nativePaneChrome: boolean): number {
|
|
85
86
|
if (!segment.icon) return 0;
|
|
86
|
-
return nativePaneChrome
|
|
87
|
+
return nativePaneChrome
|
|
88
|
+
? 3 + (segment.iconText ? segment.iconText.length + 1 : 0)
|
|
89
|
+
: Math.max(3, 1 + terminalSegmentKey(segment, focused).length);
|
|
87
90
|
}
|
|
88
91
|
|
|
89
92
|
function SegmentView({ segment, focused }: { segment: PaneFooterSegment; focused: boolean }) {
|
|
@@ -124,6 +127,7 @@ function SegmentView({ segment, focused }: { segment: PaneFooterSegment; focused
|
|
|
124
127
|
data-icon={segment.icon}
|
|
125
128
|
>
|
|
126
129
|
<Icon name={segment.icon} size={14} color={segment.disabled ? colors.textMuted : footerToneColor(segment.parts[0] ?? { text: "" })} />
|
|
130
|
+
{segment.iconText ? <Text fg={colors.textMuted} selectable={false} data-gloom-role="pane-footer-icon-text">{segment.iconText}</Text> : null}
|
|
127
131
|
</Box>
|
|
128
132
|
);
|
|
129
133
|
}
|
|
@@ -140,6 +144,7 @@ function SegmentView({ segment, focused }: { segment: PaneFooterSegment; focused
|
|
|
140
144
|
disabled={!interactive}
|
|
141
145
|
color={segment.disabled ? colors.textMuted : footerToneColor(segment.parts[0] ?? { text: "" })}
|
|
142
146
|
onPress={() => segment.onPress?.()}
|
|
147
|
+
text={segment.iconText}
|
|
143
148
|
/>
|
|
144
149
|
);
|
|
145
150
|
}
|