gloomberb 0.16.2 → 0.16.4
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 +4 -1
- package/src/api-client/askg.ts +43 -0
- package/src/api-client/auth.ts +15 -0
- package/src/api-client/beneficial-owners.ts +4 -0
- package/src/api-client/chat.ts +19 -0
- package/src/api-client/company-kpis.ts +14 -2
- package/src/api-client/data.ts +34 -16
- package/src/api-client/index.ts +12 -0
- package/src/api-client/normalizers.ts +27 -0
- package/src/api-client/paths.ts +88 -23
- package/src/api-client/request.ts +2 -1
- package/src/api-client/research-activity.ts +31 -0
- package/src/api-client/socket.ts +39 -8
- package/src/api-client/types.ts +57 -1
- package/src/api-client/upgrade-experiment.ts +90 -0
- package/src/app/global-shortcuts.ts +11 -1
- package/src/app/keybindings/actions.ts +10 -0
- package/src/app/pane-runtime/index.tsx +8 -0
- package/src/app/pane-runtime/pane-template-runtime.ts +5 -0
- package/src/app/pane-runtime/plugin-bindings.ts +65 -25
- package/src/app/pane-runtime/ticker-inspector-runtime.ts +12 -0
- package/src/app/pane-runtime/ticker-open-runtime.ts +18 -1
- package/src/app/runtime/desktop-deeplink.ts +5 -0
- package/src/app/star-prompt/model.ts +98 -0
- package/src/app/star-prompt/runtime.ts +41 -0
- package/src/app/star-prompt/status-line.tsx +190 -0
- package/src/app.tsx +13 -7
- package/src/architecture/core-builtin-allowlist.json +70 -0
- package/src/brokers/account-cache.ts +45 -0
- package/src/brokers/signed-in/adapter.ts +33 -2
- package/src/brokers/signed-in/client.ts +10 -0
- package/src/brokers/signed-in/sign-in-dialog.tsx +23 -9
- package/src/brokers/signed-in/sign-in.ts +62 -5
- package/src/capabilities/registry.ts +8 -1
- package/src/capabilities/types.ts +2 -0
- package/src/cli/command-options.ts +74 -0
- package/src/cli/commands/command-utils.ts +29 -0
- package/src/cli/commands/crypto-hints.ts +12 -4
- package/src/cli/commands/market.ts +524 -148
- package/src/cli/commands/options-chain.ts +172 -0
- package/src/cli/commands/options-leaps.ts +422 -0
- package/src/cli/commands/overview.ts +223 -42
- package/src/cli/commands/search.ts +29 -8
- package/src/cli/commands/system.ts +99 -19
- package/src/cli/commands/themes.ts +64 -0
- package/src/cli/commands/ticker.ts +200 -73
- package/src/cli/desktop-pane-shot.ts +100 -16
- package/src/cli/errors.ts +25 -2
- package/src/cli/freshness.ts +7 -4
- package/src/cli/fx-pair.ts +57 -0
- package/src/cli/help.ts +40 -7
- package/src/cli/history-rows.ts +187 -15
- package/src/cli/index-roots.ts +51 -0
- package/src/cli/index.ts +21 -13
- package/src/cli/listing-arg.ts +211 -3
- package/src/cli/not-a-ticker.ts +37 -0
- package/src/cli/options.ts +55 -7
- package/src/cli/pane-functions/capabilities.ts +13 -2
- package/src/cli/pane-functions/catalog.ts +13 -2
- package/src/cli/pane-functions/data.ts +36 -5
- package/src/cli/pane-functions/dom.ts +89 -28
- package/src/cli/pane-functions/freshness.ts +205 -26
- package/src/cli/pane-functions/function-help.ts +71 -24
- package/src/cli/pane-functions/headless.ts +168 -35
- package/src/cli/pane-functions/index.ts +12 -2
- package/src/cli/pane-functions/market-session.ts +133 -0
- package/src/cli/pane-functions/options.ts +15 -4
- package/src/cli/pane-functions/report-notices.ts +63 -0
- package/src/cli/pane-functions/report.ts +12 -1
- package/src/cli/pane-functions/resolver.ts +32 -8
- package/src/cli/pane-functions/screenshot-evidence.ts +2 -0
- package/src/cli/pane-functions/screenshot.ts +109 -23
- package/src/cli/registry.ts +8 -4
- package/src/cli/report-tables.ts +460 -0
- package/src/cli/result.ts +63 -16
- package/src/cli/row-window.ts +76 -0
- package/src/cli/scroll-truncation.ts +34 -0
- package/src/components/chart/composite/composite-chart.tsx +43 -4
- package/src/components/chart/composite/legend.tsx +39 -6
- package/src/components/chart/composite/rasterizer.ts +64 -4
- package/src/components/chart/composite/series-cues.ts +71 -0
- package/src/components/chart/composite/text-renderer.ts +16 -8
- package/src/components/chart/composite/types.ts +3 -0
- package/src/components/command-bar/commands/direct/index.ts +9 -1
- package/src/components/command-bar/commands/plugin/items.ts +3 -1
- package/src/components/command-bar/commands/registry.ts +7 -0
- package/src/components/command-bar/layout-items/focused-pane.ts +38 -0
- package/src/components/command-bar/pane-templates/workflow.ts +5 -0
- package/src/components/command-bar/routes/root/command-items.ts +2 -0
- package/src/components/command-bar/routes/root/plugin-turn-on.ts +92 -0
- package/src/components/command-bar/routes/root/results.ts +40 -10
- package/src/components/command-bar/routes/root/runtime.ts +8 -0
- package/src/components/command-bar/routes/root/search-providers.ts +97 -14
- package/src/components/command-bar/surface/index.tsx +18 -4
- package/src/components/command-bar/theme-picker.tsx +48 -13
- package/src/components/command-bar/workflow/ops.ts +5 -3
- package/src/components/data-table/export.ts +6 -51
- package/src/components/data-table/view.tsx +31 -10
- package/src/components/layout/floating-pane.tsx +6 -2
- package/src/components/layout/market-summary.ts +23 -9
- package/src/components/layout/pane/content.tsx +46 -29
- package/src/components/layout/pane/cycle-order.ts +2 -11
- package/src/components/layout/pane/header.tsx +2 -1
- package/src/components/layout/pane/title.ts +1 -1
- package/src/components/layout/presentation.ts +22 -0
- package/src/components/layout/shell/active-drag.ts +67 -35
- package/src/components/layout/shell/cursor-occlusion.ts +6 -5
- package/src/components/layout/shell/drag/index.ts +16 -7
- package/src/components/layout/shell/drag/live.ts +193 -0
- package/src/components/layout/shell/drag/overlays.tsx +179 -35
- package/src/components/layout/shell/drag/runtime.ts +62 -50
- package/src/components/layout/shell/drag/slide.ts +10 -0
- package/src/components/layout/shell/index.tsx +84 -57
- package/src/components/layout/shell/layout-state.ts +5 -11
- package/src/components/layout/shell/menu.ts +28 -1
- package/src/components/layout/shell/native/pointer-runtime.ts +13 -13
- package/src/components/layout/shell/native/surfaces.ts +30 -14
- package/src/components/layout/shell/pane/actions.ts +2 -1
- package/src/components/layout/shell/pane/layers.tsx +461 -180
- package/src/components/layout/shell/pane/management-shortcuts.ts +5 -0
- package/src/components/layout/shell/pane/new-layout.ts +116 -0
- package/src/components/layout/shell/shortcuts.ts +5 -2
- package/src/components/layout/shell/terminal-pointer-runtime.ts +18 -18
- package/src/components/layout/shell/visible-layout.ts +44 -1
- package/src/components/layout/shell/window-mode/overlays.tsx +12 -4
- package/src/components/layout/status-bar.tsx +4 -1
- package/src/components/markdown-text.tsx +9 -5
- package/src/components/metric-treemap/heat-surface.tsx +27 -8
- package/src/components/metric-treemap/heat-tiles.ts +48 -17
- package/src/components/onboarding/onboarding-frame.tsx +33 -10
- package/src/components/onboarding/onboarding-wizard.tsx +49 -40
- package/src/components/onboarding/portfolio-step/positions-panel.tsx +5 -2
- package/src/components/onboarding/pro-step-layout.ts +86 -0
- package/src/components/onboarding/use-onboarding-upgrade.ts +6 -2
- package/src/components/ui/button.tsx +10 -0
- package/src/components/ui/data-table/index.tsx +38 -0
- package/src/components/ui/data-table/types.ts +8 -1
- package/src/components/ui/data-table/visible-range.ts +2 -0
- package/src/components/ui/icon.tsx +11 -2
- package/src/components/ui/index.ts +1 -1
- package/src/core/connection-health.ts +1 -1
- package/src/core/state/app/layout-reducer.ts +89 -3
- package/src/core/state/app/state.ts +8 -5
- package/src/core/state/app/types.ts +13 -2
- package/src/data/config/layout.ts +55 -21
- package/src/data/config/store/fold-panes.ts +149 -0
- package/src/data/config/store/migrations.ts +7 -0
- package/src/data/config/store/node.ts +27 -6
- package/src/data/config/store/normalize.ts +37 -3
- package/src/data/json-persistence.ts +17 -3
- package/src/data/json-storage.ts +2 -0
- package/src/data/memory-resource-store.ts +46 -0
- package/src/i18n/es.ts +14 -1
- package/src/i18n/ja.ts +14 -1
- package/src/i18n/ko.ts +14 -1
- package/src/i18n/zh-cn.ts +14 -1
- package/src/i18n/zh-tw.ts +14 -1
- package/src/layout/desks.ts +1 -2
- package/src/layout/pane-layout-move.ts +264 -0
- package/src/layout/pane-manager/hidden-panes.ts +160 -0
- package/src/layout/pane-manager/index.ts +1 -0
- package/src/market-data/coordinator/entries.ts +7 -1
- package/src/market-data/coordinator/quotes.ts +2 -2
- package/src/market-data/market/freshness.ts +156 -11
- package/src/market-data/market/status.ts +40 -0
- package/src/market-data/options-alternatives.ts +69 -0
- package/src/market-data/quotes/contributions.ts +19 -2
- package/src/market-data/quotes/freshness.ts +5 -0
- package/src/market-data/quotes/metadata.ts +16 -0
- package/src/market-data/quotes/screener-live-quotes.ts +56 -5
- package/src/plugins/builtin/account-management/keyboard.ts +3 -0
- package/src/plugins/builtin/account-management/model.ts +1 -0
- package/src/plugins/builtin/account-management/navigation.ts +1 -1
- package/src/plugins/builtin/account-management/pane.tsx +31 -4
- package/src/plugins/builtin/alerts/quotes.ts +3 -0
- package/src/plugins/builtin/analytics/pane-model.ts +10 -6
- package/src/plugins/builtin/analytics/risk-headless.ts +3 -1
- package/src/plugins/builtin/analytics/risk-model.ts +37 -8
- package/src/plugins/builtin/analytics/risk-pane.tsx +8 -4
- package/src/plugins/builtin/attention/pane.tsx +1 -1
- package/src/plugins/builtin/backtest/pane.tsx +1 -1
- package/src/plugins/builtin/broker-manager/detail.tsx +4 -0
- package/src/plugins/builtin/broker-manager/index.tsx +7 -3
- package/src/plugins/builtin/broker-manager/model.ts +8 -0
- package/src/plugins/builtin/broker-manager/pane-actions.tsx +8 -2
- package/src/plugins/builtin/broker-manager/sign-in-end.ts +82 -0
- package/src/plugins/builtin/broker-manager/table.ts +5 -0
- package/src/plugins/builtin/builtin-plugin-meta.ts +121 -11
- package/src/plugins/builtin/catalysts/detail.tsx +1 -1
- package/src/plugins/builtin/chart-composer/pane.tsx +1 -1
- package/src/plugins/builtin/chat/channels.ts +34 -36
- package/src/plugins/builtin/chat/command-bar.ts +138 -0
- package/src/plugins/builtin/chat/composer-commands.ts +21 -1
- package/src/plugins/builtin/chat/content/composer-runtime.ts +11 -1
- package/src/plugins/builtin/chat/content/footer.tsx +5 -3
- package/src/plugins/builtin/chat/content/index.tsx +21 -1
- package/src/plugins/builtin/chat/content/mentions.ts +2 -1
- package/src/plugins/builtin/chat/content/user-map.ts +3 -1
- package/src/plugins/builtin/chat/controller/index.ts +48 -0
- package/src/plugins/builtin/chat/conversations.ts +256 -0
- package/src/plugins/builtin/chat/discord-command.ts +91 -0
- package/src/plugins/builtin/chat/edit-window.ts +12 -6
- package/src/plugins/builtin/chat/ghost-user.ts +14 -0
- package/src/plugins/builtin/chat/index.tsx +40 -2
- package/src/plugins/builtin/chat/layout.ts +2 -0
- package/src/plugins/builtin/chat/message/desktop.tsx +2 -1
- package/src/plugins/builtin/chat/message/header.tsx +24 -15
- package/src/plugins/builtin/chat/message/profile-popover.tsx +2 -1
- package/src/plugins/builtin/chat/message/render-state.ts +3 -0
- package/src/plugins/builtin/chat/pane-requests.ts +60 -0
- package/src/plugins/builtin/chat/pane-state.ts +32 -2
- package/src/plugins/builtin/chat/pane.tsx +8 -0
- package/src/plugins/builtin/cloud/askg/controller.ts +112 -4
- package/src/plugins/builtin/cloud/askg/conversation-store.ts +21 -0
- package/src/plugins/builtin/cloud/askg/manifest.ts +1 -0
- package/src/plugins/builtin/cloud/askg/model.ts +129 -70
- package/src/plugins/builtin/cloud/askg/pane.tsx +772 -377
- package/src/plugins/builtin/cloud/askg/protocol.ts +40 -2
- package/src/plugins/builtin/cloud/askg/tool-display.ts +437 -0
- package/src/plugins/builtin/cloud/askg/tool-timeline.tsx +403 -0
- package/src/plugins/builtin/cloud/company-picker.tsx +1 -9
- package/src/plugins/builtin/cloud/mcp-connect/command.ts +24 -0
- package/src/plugins/builtin/cloud/mcp-connect/dialog.tsx +360 -0
- package/src/plugins/builtin/cloud/mcp-connect/model.ts +135 -0
- package/src/plugins/builtin/cloud/mcp-connect/sections.ts +62 -0
- package/src/plugins/builtin/cloud/plugin.tsx +36 -1
- package/src/plugins/builtin/cloud/starter-symbols.ts +8 -0
- package/src/plugins/builtin/cloud/terminal-relay/acm-tab.tsx +89 -0
- package/src/plugins/builtin/cloud/terminal-relay/client.ts +97 -0
- package/src/plugins/builtin/cloud/terminal-relay/connect-section.tsx +57 -0
- package/src/plugins/builtin/cloud/terminal-relay/engine.ts +666 -0
- package/src/plugins/builtin/cloud/terminal-relay/grants.ts +137 -0
- package/src/plugins/builtin/cloud/terminal-relay/host.tsx +81 -0
- package/src/plugins/builtin/cloud/terminal-relay/indicator.tsx +82 -0
- package/src/plugins/builtin/cloud/terminal-relay/manifest.ts +234 -0
- package/src/plugins/builtin/cloud/terminal-relay/policy.ts +153 -0
- package/src/plugins/builtin/cloud/terminal-relay/prompts.tsx +168 -0
- package/src/plugins/builtin/cloud/terminal-relay/redact.ts +73 -0
- package/src/plugins/builtin/cloud/terminal-relay/summary.ts +62 -0
- package/src/plugins/builtin/cloud/upgrade-dialog.tsx +26 -2
- package/src/plugins/builtin/cloud/upgrade-personalization.ts +57 -0
- package/src/plugins/builtin/cloud/upgrade-tickers.ts +124 -0
- package/src/plugins/builtin/comment-letters/client.ts +1 -3
- package/src/plugins/builtin/company-attention/pane.tsx +1 -1
- package/src/plugins/builtin/company-kpis/client.ts +23 -8
- package/src/plugins/builtin/company-kpis/headless.ts +3 -1
- package/src/plugins/builtin/company-kpis/pane.tsx +15 -7
- package/src/plugins/builtin/company-kpis/screenshot-evidence.ts +10 -3
- package/src/plugins/builtin/composite-plugins.ts +107 -64
- package/src/plugins/builtin/credit-boards/cdx-pane.tsx +4 -4
- package/src/plugins/builtin/credit-boards/index.tsx +21 -21
- package/src/plugins/builtin/credit-boards/model.ts +0 -1
- package/src/plugins/builtin/credit-boards/pane.tsx +30 -0
- package/src/plugins/builtin/credit-boards/sovr-pane.tsx +4 -4
- package/src/plugins/builtin/debt-maturities/client.ts +37 -9
- package/src/plugins/builtin/debt-maturities/headless.ts +3 -1
- package/src/plugins/builtin/debt-maturities/pane.tsx +5 -4
- package/src/plugins/builtin/dividend-yield/index.tsx +1 -1
- package/src/plugins/builtin/dividend-yield/pane.tsx +1 -1
- package/src/plugins/builtin/earnings-calls/data.ts +28 -7
- package/src/plugins/builtin/earnings-calls/headless.ts +3 -2
- package/src/plugins/builtin/earnings-calls/pane.tsx +10 -5
- package/src/plugins/builtin/econ/calendar-model.ts +42 -17
- package/src/plugins/builtin/econ/detail-view.tsx +2 -2
- package/src/plugins/builtin/econ/index.tsx +68 -22
- package/src/plugins/builtin/econ-statistics/headless.ts +12 -2
- package/src/plugins/builtin/econ-statistics/pane.tsx +1 -1
- package/src/plugins/builtin/econ-statistics/view.ts +17 -0
- package/src/plugins/builtin/executives/data.ts +17 -6
- package/src/plugins/builtin/executives/pane.tsx +16 -7
- package/src/plugins/builtin/filing-events/pane.tsx +22 -5
- package/src/plugins/builtin/fx-matrix/freshness.ts +65 -0
- package/src/plugins/builtin/fx-matrix/index.tsx +22 -1
- package/src/plugins/builtin/fx-matrix/pairs.ts +1 -1
- package/src/plugins/builtin/fx-matrix/settings.ts +42 -2
- package/src/plugins/builtin/gpu/headless.ts +9 -3
- package/src/plugins/builtin/gpu/model.ts +14 -5
- package/src/plugins/builtin/help/index.tsx +1 -0
- package/src/plugins/builtin/holders/beneficial-client.ts +29 -7
- package/src/plugins/builtin/holders/beneficial-view.tsx +7 -3
- package/src/plugins/builtin/holders/client.ts +3 -6
- package/src/plugins/builtin/holders/format.ts +31 -1
- package/src/plugins/builtin/holders/headless.ts +32 -6
- package/src/plugins/builtin/holders/pane.tsx +25 -13
- package/src/plugins/builtin/holders/report-header.ts +46 -5
- package/src/plugins/builtin/insider/index.tsx +4 -4
- package/src/plugins/builtin/iv-history/charts.tsx +21 -7
- package/src/plugins/builtin/iv-history/client.ts +12 -2
- package/src/plugins/builtin/iv-history/format.ts +33 -2
- package/src/plugins/builtin/iv-history/headless.ts +22 -10
- package/src/plugins/builtin/iv-history/index.tsx +3 -3
- package/src/plugins/builtin/iv-history/model.ts +61 -13
- package/src/plugins/builtin/iv-history/pane.tsx +11 -3
- package/src/plugins/builtin/iv-history/screen-pane.tsx +42 -18
- package/src/plugins/builtin/jobs/pane.tsx +1 -1
- package/src/plugins/builtin/kelly-sizer/headless.ts +149 -0
- package/src/plugins/builtin/kelly-sizer/history.ts +80 -0
- package/src/plugins/builtin/kelly-sizer/index.tsx +2 -0
- package/src/plugins/builtin/kelly-sizer/pane.tsx +121 -45
- package/src/plugins/builtin/kelly-sizer/portfolio.ts +25 -0
- package/src/plugins/builtin/kelly-sizer/sections.tsx +14 -0
- package/src/plugins/builtin/kelly-sizer/types.ts +9 -1
- package/src/plugins/builtin/layout-manager/index.tsx +9 -1
- package/src/plugins/builtin/macro-day/client.ts +24 -0
- package/src/plugins/builtin/macro-day/headless.ts +11 -8
- package/src/plugins/builtin/macro-day/index.tsx +3 -0
- package/src/plugins/builtin/macro-day/model.ts +11 -6
- package/src/plugins/builtin/macro-day/pane.tsx +12 -8
- package/src/plugins/builtin/macro-day/release-table.ts +40 -0
- package/src/plugins/builtin/macro-day/releases.ts +62 -44
- package/src/plugins/builtin/market-heatmap/data.ts +25 -5
- package/src/plugins/builtin/market-heatmap/evidence.ts +90 -0
- package/src/plugins/builtin/market-heatmap/index.tsx +144 -63
- package/src/plugins/builtin/market-heatmap/model.ts +94 -3
- package/src/plugins/builtin/market-heatmap/portfolio.ts +12 -2
- package/src/plugins/builtin/market-movers/headless.ts +31 -4
- package/src/plugins/builtin/market-movers/index.tsx +8 -1
- package/src/plugins/builtin/market-movers/model.ts +71 -17
- package/src/plugins/builtin/market-movers/table.ts +50 -23
- package/src/plugins/builtin/members/pane.tsx +10 -0
- package/src/plugins/builtin/news/headless.ts +9 -2
- package/src/plugins/builtin/news/wire/news/footer.ts +10 -0
- package/src/plugins/builtin/openfda/client.ts +1 -1
- package/src/plugins/builtin/options/carry.ts +95 -0
- package/src/plugins/builtin/options/index.tsx +58 -5
- package/src/plugins/builtin/options/strike-window.ts +183 -0
- package/src/plugins/builtin/options/table.ts +55 -3
- package/src/plugins/builtin/options/types.ts +8 -1
- package/src/plugins/builtin/options/view.tsx +161 -12
- package/src/plugins/builtin/options-positioning/headless.ts +4 -2
- package/src/plugins/builtin/options-scenario/charts.tsx +2 -2
- package/src/plugins/builtin/options-scenario/client.ts +73 -17
- package/src/plugins/builtin/options-scenario/headless.ts +71 -24
- package/src/plugins/builtin/options-scenario/hedge.ts +284 -0
- package/src/plugins/builtin/options-scenario/index.tsx +9 -2
- package/src/plugins/builtin/options-scenario/model.ts +33 -0
- package/src/plugins/builtin/options-scenario/pane.tsx +40 -16
- package/src/plugins/builtin/pe-band/model.ts +2 -2
- package/src/plugins/builtin/pe-band/report-dates.ts +11 -7
- package/src/plugins/builtin/perps/equity-row.tsx +8 -5
- package/src/plugins/builtin/perps/model.ts +16 -5
- package/src/plugins/builtin/perps/pane.tsx +1 -1
- package/src/plugins/builtin/plugin-marketplace/model.ts +64 -21
- package/src/plugins/builtin/plugin-marketplace/packs.ts +118 -0
- package/src/plugins/builtin/plugin-marketplace/pane.tsx +344 -32
- package/src/plugins/builtin/plugin-marketplace/store.ts +7 -1
- package/src/plugins/builtin/plugin-module.ts +87 -4
- package/src/plugins/builtin/portfolio-list/account-metrics.ts +16 -1
- package/src/plugins/builtin/portfolio-list/allocation.ts +3 -0
- package/src/plugins/builtin/portfolio-list/cached-account.ts +18 -9
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +71 -36
- package/src/plugins/builtin/portfolio-list/cli/render.ts +89 -18
- package/src/plugins/builtin/portfolio-list/cli/shared.ts +2 -16
- package/src/plugins/builtin/portfolio-list/headless.ts +40 -7
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +7 -4
- package/src/plugins/builtin/portfolio-list/summary/index.tsx +22 -4
- package/src/plugins/builtin/portfolio-list/summary/live-accounts.ts +11 -1
- package/src/plugins/builtin/realized-vol/headless.ts +3 -0
- package/src/plugins/builtin/realized-vol/pane.tsx +1 -1
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +2 -2
- package/src/plugins/builtin/research/equity-diagnostic-pane.tsx +1 -1
- package/src/plugins/builtin/research/relative-valuation-model.ts +7 -3
- package/src/plugins/builtin/revenue-breakdown/client.ts +13 -6
- package/src/plugins/builtin/revenue-breakdown/headless.ts +4 -1
- package/src/plugins/builtin/revenue-breakdown/pane.tsx +7 -4
- package/src/plugins/builtin/reverse-dcf/headless.ts +5 -1
- package/src/plugins/builtin/reverse-dcf/model.ts +2 -1
- package/src/plugins/builtin/reverse-dcf/pane.tsx +1 -1
- package/src/plugins/builtin/risk-factors/data.ts +23 -9
- package/src/plugins/builtin/risk-factors/headless.ts +5 -2
- package/src/plugins/builtin/risk-factors/pane.tsx +6 -5
- package/src/plugins/builtin/seasonality/pane.tsx +1 -1
- package/src/plugins/builtin/sec/index.tsx +5 -5
- package/src/plugins/builtin/sectors/client.ts +10 -2
- package/src/plugins/builtin/sectors/headless.ts +35 -6
- package/src/plugins/builtin/sectors/index.tsx +18 -1
- package/src/plugins/builtin/sectors/sector-model.ts +150 -41
- package/src/plugins/builtin/shared/command-tab.ts +51 -0
- package/src/plugins/builtin/shared/headless-market-data.ts +33 -1
- package/src/plugins/builtin/shared/members-menu.tsx +260 -0
- package/src/plugins/builtin/shared/report-freshness.ts +50 -2
- package/src/plugins/builtin/shared/ticker-request.ts +25 -1
- package/src/plugins/builtin/shared/use-quote-board.ts +25 -5
- package/src/plugins/builtin/shared/volatility/options.ts +1 -46
- package/src/plugins/builtin/short-interest/index.tsx +19 -4
- package/src/plugins/builtin/short-interest/surface.tsx +4 -4
- package/src/plugins/builtin/short-volume/index.tsx +1 -10
- package/src/plugins/builtin/short-volume/pane.tsx +1 -1
- package/src/plugins/builtin/social-mentions/pane.tsx +1 -1
- package/src/plugins/builtin/supply-chain/model.ts +1 -1
- package/src/plugins/builtin/themes/pane.tsx +3 -0
- package/src/plugins/builtin/ticker-detail/financials/aggregation.ts +4 -0
- package/src/plugins/builtin/ticker-detail/financials/model.ts +25 -2
- package/src/plugins/builtin/ticker-detail/headless.ts +63 -25
- package/src/plugins/builtin/ticker-detail/overview/model.ts +9 -4
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +3 -2
- package/src/plugins/builtin/ticker-detail/pane.tsx +4 -5
- package/src/plugins/builtin/ticker-detail/quote-monitor/card.tsx +94 -6
- package/src/plugins/builtin/treasury-auctions/cache.ts +5 -2
- package/src/plugins/builtin/treasury-auctions/client.ts +22 -8
- package/src/plugins/builtin/treasury-auctions/headless.ts +40 -4
- package/src/plugins/builtin/treasury-auctions/index.tsx +11 -9
- package/src/plugins/builtin/treasury-auctions/model.ts +197 -30
- package/src/plugins/builtin/treasury-auctions/pane.tsx +35 -11
- package/src/plugins/builtin/treasury-auctions/types.ts +11 -1
- package/src/plugins/builtin/vol-surface/charts.tsx +1 -3
- package/src/plugins/builtin/vol-surface/client.ts +6 -2
- package/src/plugins/builtin/vol-surface/evidence.ts +11 -6
- package/src/plugins/builtin/vol-surface/headless.ts +124 -20
- package/src/plugins/builtin/vol-surface/model.ts +23 -11
- package/src/plugins/builtin/vol-surface/pane.tsx +38 -27
- package/src/plugins/builtin/vol-surface/tables.ts +124 -0
- package/src/plugins/builtin/world-indices/client.ts +22 -4
- package/src/plugins/builtin/world-indices/headless.ts +54 -27
- package/src/plugins/builtin/world-indices/model.ts +4 -2
- package/src/plugins/builtin/world-indices/table.tsx +13 -2
- package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +2 -0
- package/src/plugins/builtin/world-venue-map/basemap.ts +18 -0
- package/src/plugins/builtin/world-venue-map/country-labels.ts +78 -0
- package/src/plugins/builtin/world-venue-map/geo-series.ts +1 -1
- package/src/plugins/builtin/world-venue-map/geo-svg.tsx +2 -1
- package/src/plugins/builtin/world-venue-map/index.ts +6 -6
- package/src/plugins/builtin/world-venue-map/layered-pane.tsx +27 -14
- package/src/plugins/builtin/world-venue-map/layers.ts +68 -10
- package/src/plugins/builtin/world-venue-map/map.tsx +198 -62
- package/src/plugins/builtin/world-venue-map/model.ts +16 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/index.chunk.ts +3 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/labels.chunk.ts +244 -0
- package/src/plugins/builtin/world-venue-map/pane.tsx +16 -10
- package/src/plugins/builtin/yield-curve/index.tsx +1 -1
- package/src/plugins/builtin-editorial.ts +126 -0
- package/src/plugins/catalog-backend.ts +16 -9
- package/src/plugins/catalog-browser.ts +127 -63
- package/src/plugins/catalog-manifest.ts +73 -40
- package/src/plugins/catalog-ui.ts +26 -6
- package/src/plugins/extracted-plugins.ts +7 -1
- package/src/plugins/ownership.ts +150 -7
- package/src/plugins/plugin-functions.ts +54 -0
- package/src/plugins/plugin-off.ts +36 -0
- package/src/plugins/registry/host-actions.ts +16 -0
- package/src/plugins/registry/index.ts +84 -24
- package/src/plugins/registry/plugin-state.ts +25 -1
- package/src/plugins/runtime/context.tsx +29 -0
- package/src/react/input.ts +48 -1
- package/src/remote/app-host.tsx +5 -0
- package/src/remote/controller.ts +3 -53
- package/src/remote/matching.ts +69 -0
- package/src/remote/schema.ts +1 -1
- package/src/remote/semantic-tree.tsx +14 -0
- package/src/remote/types.ts +2 -0
- package/src/renderers/browser/app-services.ts +3 -1
- package/src/renderers/dom/data-table/dom.ts +31 -0
- package/src/renderers/dom/data-table/index.tsx +5 -0
- package/src/renderers/dom/desktop/icons.tsx +14 -0
- package/src/renderers/dom/desktop/query-bar.tsx +59 -32
- package/src/renderers/dom/host/box.tsx +113 -17
- package/src/renderers/dom/host/drag-shield.ts +35 -0
- package/src/renderers/dom/host/live-frame.ts +62 -0
- package/src/renderers/dom/host/mouse.ts +8 -1
- package/src/renderers/dom/host/scroll-box.tsx +6 -5
- package/src/renderers/dom/host/tabs.tsx +3 -2
- package/src/renderers/dom/input-host.tsx +6 -1
- package/src/renderers/dom/styles.css +26 -5
- package/src/renderers/electrobun/bun/desktop/backend-requests.ts +7 -0
- package/src/renderers/electrobun/bun/desktop/backend.ts +7 -1
- package/src/renderers/electrobun/bun/desktop/detached-windows.ts +12 -1
- package/src/renderers/electrobun/bun/desktop/initialization.ts +15 -1
- package/src/renderers/electrobun/shared/protocol.ts +12 -1
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +4 -1
- package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +101 -5
- package/src/renderers/electrobun/view/host/native.ts +0 -10
- package/src/renderers/electrobun/view/host/window-move.ts +28 -0
- package/src/renderers/electrobun/view/main.tsx +4 -1
- package/src/renderers/electrobun/view/remote/persistence.ts +15 -2
- package/src/renderers/electrobun/view/ui-host.tsx +2 -5
- package/src/renderers/opentui/input-host.tsx +6 -1
- package/src/renderers/opentui/start.tsx +9 -0
- package/src/renderers/opentui/ui-host.tsx +7 -1
- package/src/shares/portable-layout.ts +16 -6
- package/src/sources/gloomberb-cloud/index.ts +19 -10
- package/src/sources/gloomberb-cloud/normalizers.ts +20 -21
- package/src/sources/listing-symbols.ts +11 -5
- package/src/sources/provider-errors.ts +88 -3
- package/src/sources/provider-router/batches.ts +3 -3
- package/src/sources/provider-router/cached-routes.ts +8 -4
- package/src/sources/provider-router/financial-routes.ts +13 -7
- package/src/sources/provider-router/financials.ts +106 -16
- package/src/sources/provider-router/history.ts +27 -11
- package/src/sources/provider-router/index.ts +1 -1
- package/src/sources/provider-router/primary.ts +24 -6
- package/src/sources/sec-edgar.ts +68 -8
- package/src/state/pane-scroll-registry.tsx +67 -35
- package/src/sync/core-contributors.ts +4 -3
- package/src/test-support/cli-context.ts +2 -1
- package/src/test-support/data-provider.ts +34 -0
- package/src/test-support/margin-account.ts +108 -0
- package/src/test-support/shell-pane-keys.tsx +1 -0
- package/src/theme/series-colors.ts +46 -0
- package/src/theme/themes.ts +149 -0
- package/src/tickers/search/index.ts +22 -2
- package/src/tickers/search/ranking.ts +45 -1
- package/src/tickers/search/types.ts +3 -1
- package/src/time-series/resolution.ts +15 -0
- package/src/time-series/resolve.ts +1 -14
- package/src/types/config.ts +61 -1
- package/src/types/financials.ts +32 -3
- package/src/types/headless.ts +11 -0
- package/src/types/instrument.ts +8 -0
- package/src/types/plugin.ts +49 -3
- package/src/ui/host.tsx +16 -0
- package/src/ui/index.tsx +10 -3
- package/src/ui/scroll-box-axis.ts +26 -0
- package/src/utils/cli-output.ts +14 -1
- package/src/utils/currency-units.ts +8 -3
- package/src/utils/depositary-receipt.ts +54 -10
- package/src/utils/display-number.ts +63 -0
- package/src/utils/exchanges.ts +13 -0
- package/src/utils/format.ts +2 -1
- package/src/utils/fundamentals.ts +17 -1
- package/src/utils/fx-market-hours.ts +34 -0
- package/src/utils/option-expiry.ts +126 -0
- package/src/utils/price-history-integrity.ts +19 -6
- package/src/utils/price-history.ts +39 -6
- package/src/utils/rpc-timeout-error.ts +6 -2
- package/src/utils/sec-eps-basis.ts +159 -30
- package/src/utils/sec.ts +38 -34
- package/src/utils/throttled-fetch.ts +51 -22
package/src/remote/controller.ts
CHANGED
|
@@ -30,6 +30,7 @@ import type {
|
|
|
30
30
|
} from "./types";
|
|
31
31
|
import type { RemoteUiRegistry } from "./semantic-tree";
|
|
32
32
|
import { commandBarResultsFromNodes, isCommandBarInputNode } from "./command-bar";
|
|
33
|
+
import { findCommandBarResult, findMatchingUiNode } from "./matching";
|
|
33
34
|
import { REMOTE_AGENT_HELP, remoteControlSchema } from "./schema";
|
|
34
35
|
import {
|
|
35
36
|
fail,
|
|
@@ -48,7 +49,6 @@ import {
|
|
|
48
49
|
} from "./layout-helpers";
|
|
49
50
|
import { createRemoteResources } from "./resources";
|
|
50
51
|
import { dismissTopmostDialog, isDialogOpen as isAnyDialogOpen } from "../ui/dialog-stack";
|
|
51
|
-
import { findFormNode } from "./form";
|
|
52
52
|
import { asRecord } from "../utils/guards";
|
|
53
53
|
import { runAutomated } from "../telemetry/usage-counts";
|
|
54
54
|
|
|
@@ -247,20 +247,7 @@ export function createAppRemoteController({
|
|
|
247
247
|
};
|
|
248
248
|
|
|
249
249
|
const activateCommandBarResult = async (input: Record<string, unknown>): Promise<unknown> => {
|
|
250
|
-
const
|
|
251
|
-
const index = optionalNumber(input, "index");
|
|
252
|
-
const itemId = optionalString(input, "itemId");
|
|
253
|
-
const label = optionalString(input, "label");
|
|
254
|
-
const results = commandBarResultsFromNodes(uiRegistry?.snapshot() ?? []);
|
|
255
|
-
const result = nodeId
|
|
256
|
-
? results.find((entry) => entry.nodeId === nodeId)
|
|
257
|
-
: itemId
|
|
258
|
-
? results.find((entry) => entry.itemId === itemId)
|
|
259
|
-
: label
|
|
260
|
-
? results.find((entry) => entry.label === label)
|
|
261
|
-
: typeof index === "number"
|
|
262
|
-
? results.find((entry) => entry.index === index)
|
|
263
|
-
: results.find((entry) => entry.selected) ?? results[0];
|
|
250
|
+
const result = findCommandBarResult(commandBarResultsFromNodes(uiRegistry?.snapshot() ?? []), input);
|
|
264
251
|
if (!result) throw new Error("No matching command-bar result is visible.");
|
|
265
252
|
if (!result.actions.includes("activate")) {
|
|
266
253
|
throw new Error(`Command-bar result "${result.nodeId}" does not expose activate.`);
|
|
@@ -270,45 +257,8 @@ export function createAppRemoteController({
|
|
|
270
257
|
};
|
|
271
258
|
|
|
272
259
|
const invokeMatchingUiNode = async (input: Record<string, unknown>): Promise<unknown> => {
|
|
273
|
-
const role = optionalString(input, "role");
|
|
274
|
-
const label = optionalString(input, "label");
|
|
275
|
-
const contains = optionalString(input, "contains");
|
|
276
|
-
const index = optionalNumber(input, "index");
|
|
277
260
|
const action = optionalString(input, "action") ?? "press";
|
|
278
|
-
const
|
|
279
|
-
const nodes = uiRegistry?.snapshot() ?? [];
|
|
280
|
-
// A dialog over the form (a listing picker, a sign-in) keeps its controls
|
|
281
|
-
// out of reach, as it does from the mouse.
|
|
282
|
-
const formCovered = findFormNode(nodes)?.metadata?.covered === true;
|
|
283
|
-
const candidates = nodes.filter((node) => {
|
|
284
|
-
if (formCovered && node.metadata?.scope === "form") return false;
|
|
285
|
-
if (role && node.role !== role) return false;
|
|
286
|
-
if (label && node.label !== label && node.metadata?.item && typeof node.metadata.item === "object") {
|
|
287
|
-
const item = node.metadata.item as Record<string, unknown>;
|
|
288
|
-
if (item.label !== label && item.id !== label) return false;
|
|
289
|
-
} else if (label && node.label !== label) {
|
|
290
|
-
return false;
|
|
291
|
-
}
|
|
292
|
-
if (contains) {
|
|
293
|
-
const haystack = [
|
|
294
|
-
node.label,
|
|
295
|
-
node.role,
|
|
296
|
-
JSON.stringify(node.metadata ?? {}),
|
|
297
|
-
].filter((entry): entry is string => typeof entry === "string").join(" ").toLowerCase();
|
|
298
|
-
if (!haystack.includes(contains.toLowerCase())) return false;
|
|
299
|
-
}
|
|
300
|
-
for (const [key, value] of Object.entries(metadataFilter)) {
|
|
301
|
-
if (node.metadata?.[key] !== value) return false;
|
|
302
|
-
}
|
|
303
|
-
if (!node.actions.includes(action)) return false;
|
|
304
|
-
if (node.disabled) return false;
|
|
305
|
-
return true;
|
|
306
|
-
});
|
|
307
|
-
// An open form or confirm covers every pane, so its own controls come
|
|
308
|
-
// first: its Cancel, not a pane's Cancel behind it.
|
|
309
|
-
const inForm = candidates.filter((node) => node.metadata?.scope === "form");
|
|
310
|
-
const matches = inForm.length > 0 ? inForm : candidates;
|
|
311
|
-
const node = typeof index === "number" ? matches[index] : matches[0];
|
|
261
|
+
const node = findMatchingUiNode(uiRegistry?.snapshot() ?? [], input);
|
|
312
262
|
if (!node) throw new Error("No matching semantic UI node is visible.");
|
|
313
263
|
const result = await uiRegistry?.invoke(node.id, action, input.input);
|
|
314
264
|
return getAfterMutationSummary({ invokedNode: node, result });
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { optionalNumber, optionalString } from "./controller-utils";
|
|
2
|
+
import { findFormNode } from "./form";
|
|
3
|
+
import type { RemoteUiNodeSnapshot } from "./types";
|
|
4
|
+
import { asRecord } from "../utils/guards";
|
|
5
|
+
|
|
6
|
+
/** The visible command-bar row commandBar.activateResult picks for this input. */
|
|
7
|
+
export function findCommandBarResult<T extends { nodeId: string; itemId?: unknown; label?: unknown; index?: unknown; selected: boolean }>(
|
|
8
|
+
results: readonly T[],
|
|
9
|
+
input: Record<string, unknown>,
|
|
10
|
+
): T | undefined {
|
|
11
|
+
const nodeId = optionalString(input, "nodeId");
|
|
12
|
+
const index = optionalNumber(input, "index");
|
|
13
|
+
const itemId = optionalString(input, "itemId");
|
|
14
|
+
const label = optionalString(input, "label");
|
|
15
|
+
return nodeId
|
|
16
|
+
? results.find((entry) => entry.nodeId === nodeId)
|
|
17
|
+
: itemId
|
|
18
|
+
? results.find((entry) => entry.itemId === itemId)
|
|
19
|
+
: label
|
|
20
|
+
? results.find((entry) => entry.label === label)
|
|
21
|
+
: typeof index === "number"
|
|
22
|
+
? results.find((entry) => entry.index === index)
|
|
23
|
+
: results.find((entry) => entry.selected) ?? results[0];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** The semantic UI node ui.invokeMatching acts on for this input, or undefined. */
|
|
27
|
+
export function findMatchingUiNode(
|
|
28
|
+
nodes: RemoteUiNodeSnapshot[],
|
|
29
|
+
input: Record<string, unknown>,
|
|
30
|
+
): RemoteUiNodeSnapshot | undefined {
|
|
31
|
+
const role = optionalString(input, "role");
|
|
32
|
+
const label = optionalString(input, "label");
|
|
33
|
+
const contains = optionalString(input, "contains");
|
|
34
|
+
const index = optionalNumber(input, "index");
|
|
35
|
+
const action = optionalString(input, "action") ?? "press";
|
|
36
|
+
const metadataFilter = asRecord(input.metadata);
|
|
37
|
+
// A dialog over the form (a listing picker, a sign-in) keeps its controls
|
|
38
|
+
// out of reach, as it does from the mouse.
|
|
39
|
+
const formCovered = findFormNode(nodes)?.metadata?.covered === true;
|
|
40
|
+
const candidates = nodes.filter((node) => {
|
|
41
|
+
if (formCovered && node.metadata?.scope === "form") return false;
|
|
42
|
+
if (role && node.role !== role) return false;
|
|
43
|
+
if (label && node.label !== label && node.metadata?.item && typeof node.metadata.item === "object") {
|
|
44
|
+
const item = node.metadata.item as Record<string, unknown>;
|
|
45
|
+
if (item.label !== label && item.id !== label) return false;
|
|
46
|
+
} else if (label && node.label !== label) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
if (contains) {
|
|
50
|
+
const haystack = [
|
|
51
|
+
node.label,
|
|
52
|
+
node.role,
|
|
53
|
+
JSON.stringify(node.metadata ?? {}),
|
|
54
|
+
].filter((entry): entry is string => typeof entry === "string").join(" ").toLowerCase();
|
|
55
|
+
if (!haystack.includes(contains.toLowerCase())) return false;
|
|
56
|
+
}
|
|
57
|
+
for (const [key, value] of Object.entries(metadataFilter)) {
|
|
58
|
+
if (node.metadata?.[key] !== value) return false;
|
|
59
|
+
}
|
|
60
|
+
if (!node.actions.includes(action)) return false;
|
|
61
|
+
if (node.disabled) return false;
|
|
62
|
+
return true;
|
|
63
|
+
});
|
|
64
|
+
// An open form or confirm covers every pane, so its own controls come
|
|
65
|
+
// first: its Cancel, not a pane's Cancel behind it.
|
|
66
|
+
const inForm = candidates.filter((node) => node.metadata?.scope === "form");
|
|
67
|
+
const matches = inForm.length > 0 ? inForm : candidates;
|
|
68
|
+
return typeof index === "number" ? matches[index] : matches[0];
|
|
69
|
+
}
|
package/src/remote/schema.ts
CHANGED
|
@@ -115,7 +115,7 @@ export const REMOTE_OPERATIONS: RemoteOperationSchema[] = [
|
|
|
115
115
|
op("pane.close", "Close a pane instance or pane type.", "{ paneId: string }", "local-write", paneIdInput),
|
|
116
116
|
op(
|
|
117
117
|
"pane.createFromTemplate",
|
|
118
|
-
"
|
|
118
|
+
"Open a pane from a registered template. It only opens the pane: it adds nothing to a portfolio or watchlist.",
|
|
119
119
|
"{ templateId: string, options?: object }",
|
|
120
120
|
"local-write",
|
|
121
121
|
objectSchema({ templateId: requiredStringSchema, options: openObjectSchema }, ["templateId"]),
|
|
@@ -11,6 +11,8 @@ type RemoteUiAction = (input?: unknown) => unknown | Promise<unknown>;
|
|
|
11
11
|
|
|
12
12
|
export interface RemoteUiNodeRegistration {
|
|
13
13
|
role: string;
|
|
14
|
+
/** The pane instance the node is drawn in, set from RemoteUiPaneScope. */
|
|
15
|
+
paneId?: string;
|
|
14
16
|
label?: string;
|
|
15
17
|
disabled?: boolean;
|
|
16
18
|
actions?: Record<string, RemoteUiAction | undefined>;
|
|
@@ -56,6 +58,7 @@ export function createRemoteUiRegistry(): RemoteUiRegistry {
|
|
|
56
58
|
.map(([action]) => action)
|
|
57
59
|
.sort(),
|
|
58
60
|
metadata: registration.getMetadata?.() ?? registration.metadata,
|
|
61
|
+
...(registration.paneId ? { paneId: registration.paneId } : {}),
|
|
59
62
|
};
|
|
60
63
|
});
|
|
61
64
|
},
|
|
@@ -110,6 +113,13 @@ export function useRemoteUiScope(): string | null {
|
|
|
110
113
|
return useContext(RemoteUiScopeContext);
|
|
111
114
|
}
|
|
112
115
|
|
|
116
|
+
const RemoteUiPaneContext = createContext<string | null>(null);
|
|
117
|
+
|
|
118
|
+
/** Tags the nodes drawn below with the pane instance they belong to. */
|
|
119
|
+
export function RemoteUiPaneScope({ paneId, children }: { paneId: string; children: ReactNode }) {
|
|
120
|
+
return <RemoteUiPaneContext value={paneId}>{children}</RemoteUiPaneContext>;
|
|
121
|
+
}
|
|
122
|
+
|
|
113
123
|
let nextRemoteNodeSequence = 0;
|
|
114
124
|
|
|
115
125
|
/**
|
|
@@ -120,9 +130,12 @@ let nextRemoteNodeSequence = 0;
|
|
|
120
130
|
*/
|
|
121
131
|
export function useRemoteUiNode(registration: RemoteUiNodeRegistration | null | undefined): string | null {
|
|
122
132
|
const registry = useRemoteUiRegistry();
|
|
133
|
+
const paneId = useContext(RemoteUiPaneContext);
|
|
123
134
|
const nodeIdRef = useRef<string | null>(null);
|
|
124
135
|
const registrationRef = useRef(registration);
|
|
125
136
|
registrationRef.current = registration;
|
|
137
|
+
const paneIdRef = useRef(paneId);
|
|
138
|
+
paneIdRef.current = paneId;
|
|
126
139
|
const dynamicRegistrationRef = useRef<RemoteUiNodeRegistration | null>(null);
|
|
127
140
|
const registered = registration != null;
|
|
128
141
|
if (registered && !nodeIdRef.current) {
|
|
@@ -130,6 +143,7 @@ export function useRemoteUiNode(registration: RemoteUiNodeRegistration | null |
|
|
|
130
143
|
nodeIdRef.current = `ui:${nextRemoteNodeSequence.toString(36)}`;
|
|
131
144
|
dynamicRegistrationRef.current = {
|
|
132
145
|
get role() { return registrationRef.current?.role ?? "unknown"; },
|
|
146
|
+
get paneId() { return registrationRef.current?.paneId ?? paneIdRef.current ?? undefined; },
|
|
133
147
|
get label() { return registrationRef.current?.label; },
|
|
134
148
|
get disabled() { return registrationRef.current?.disabled; },
|
|
135
149
|
get actions() { return registrationRef.current?.actions; },
|
package/src/remote/types.ts
CHANGED
|
@@ -172,6 +172,8 @@ export interface RemoteControlSchema {
|
|
|
172
172
|
export interface RemoteUiNodeSnapshot {
|
|
173
173
|
id: string;
|
|
174
174
|
role: string;
|
|
175
|
+
/** The pane instance the node is drawn in; absent outside panes. */
|
|
176
|
+
paneId?: string;
|
|
175
177
|
label?: string;
|
|
176
178
|
disabled?: boolean;
|
|
177
179
|
actions: string[];
|
|
@@ -5,6 +5,7 @@ import { createAppRuntime } from "../../core/app-runtime";
|
|
|
5
5
|
import { createGloomberbCloudCapabilities, createGloomberbCloudProvider } from "../../sources/gloomberb-cloud";
|
|
6
6
|
import { AssetDataRouter } from "../../sources/provider-router";
|
|
7
7
|
import { JsonPersistence } from "../../data/json-persistence";
|
|
8
|
+
import { isBrokerAccountSnapshotKey } from "../../brokers/account-cache";
|
|
8
9
|
import { JsonTickerRepository } from "../../data/json-ticker-repository";
|
|
9
10
|
|
|
10
11
|
export function createBrowserAppServices({ config, plugins, externalPlugins }: AppServicesFactoryOptions) {
|
|
@@ -15,7 +16,8 @@ export function createBrowserAppServices({ config, plugins, externalPlugins }: A
|
|
|
15
16
|
);
|
|
16
17
|
return createAppRuntime({
|
|
17
18
|
config, plugins, externalPlugins, dataProvider,
|
|
18
|
-
|
|
19
|
+
// Broker account snapshots are kept with the positions, so a reload keeps the account's equity and cash.
|
|
20
|
+
persistence: new JsonPersistence(localStorage, { keepResource: isBrokerAccountSnapshotKey }),
|
|
19
21
|
tickerRepository: new JsonTickerRepository(localStorage),
|
|
20
22
|
configure({ pluginRegistry, newsService }) {
|
|
21
23
|
dataProvider.attachRegistry(pluginRegistry);
|
|
@@ -143,6 +143,24 @@ export function useScrollBoxHandle(
|
|
|
143
143
|
get scrollWidth() {
|
|
144
144
|
return toCellX(elementRef.current?.scrollWidth ?? 0);
|
|
145
145
|
},
|
|
146
|
+
// Whole rows are rounded, so the scroll keys read the ends in pixels.
|
|
147
|
+
get scrollTopPx() {
|
|
148
|
+
return options.headerOnly ? 0 : Math.max(0, elementRef.current?.scrollTop ?? 0);
|
|
149
|
+
},
|
|
150
|
+
get scrollHeightPx() {
|
|
151
|
+
const element = elementRef.current;
|
|
152
|
+
if (!element) return 0;
|
|
153
|
+
return options.headerOnly ? tableHeaderPx() : Math.max(0, element.scrollHeight - (options.viewportTopInsetPx ?? 0));
|
|
154
|
+
},
|
|
155
|
+
get viewportPx() {
|
|
156
|
+
const element = elementRef.current;
|
|
157
|
+
return {
|
|
158
|
+
width: Math.max(0, element?.clientWidth ?? 0),
|
|
159
|
+
height: options.headerOnly
|
|
160
|
+
? tableHeaderPx()
|
|
161
|
+
: Math.max(0, (element?.clientHeight ?? 0) - (options.viewportTopInsetPx ?? 0)),
|
|
162
|
+
};
|
|
163
|
+
},
|
|
146
164
|
get viewport() {
|
|
147
165
|
const element = elementRef.current;
|
|
148
166
|
if (options.headerOnly) {
|
|
@@ -161,6 +179,19 @@ export function useScrollBoxHandle(
|
|
|
161
179
|
},
|
|
162
180
|
horizontalScrollBar,
|
|
163
181
|
verticalScrollBar,
|
|
182
|
+
scrollToPixels(target: number | { x?: number; y?: number }, y?: number) {
|
|
183
|
+
const element = elementRef.current;
|
|
184
|
+
if (!element || options.headerOnly) return;
|
|
185
|
+
if (typeof target === "number") {
|
|
186
|
+
element.scrollTop = Math.max(0, target);
|
|
187
|
+
if (typeof y === "number") element.scrollLeft = Math.max(0, y);
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
element.scrollTo({
|
|
191
|
+
left: Math.max(0, target.x ?? element.scrollLeft),
|
|
192
|
+
top: Math.max(0, target.y ?? element.scrollTop),
|
|
193
|
+
});
|
|
194
|
+
},
|
|
164
195
|
scrollTo(target: number | { x?: number; y?: number }, y?: number) {
|
|
165
196
|
const element = elementRef.current;
|
|
166
197
|
if (!element) return;
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
} from "react";
|
|
12
12
|
import { EmptyState } from "../../../components/ui/status";
|
|
13
13
|
import { usePaneInstance } from "../../../state/app/context";
|
|
14
|
+
import { useRegisterPaneScrollBox } from "../../../state/pane-scroll-registry";
|
|
14
15
|
import { useRafCallback } from "../../../react/use-raf-callback";
|
|
15
16
|
import { measurePerf } from "../../../utils/perf-marks";
|
|
16
17
|
import type {
|
|
@@ -284,6 +285,10 @@ export function WebDataTable<T, C extends DataTableColumn = DataTableColumn>({
|
|
|
284
285
|
bodyVertical.bar,
|
|
285
286
|
{ viewportTopInsetPx: headerPx },
|
|
286
287
|
);
|
|
288
|
+
// The terminal table body is a ScrollBox the pane scroll keys already reach;
|
|
289
|
+
// this is the same for the desktop one. A table with a cursor takes the keys
|
|
290
|
+
// first, so only a table without one is scrolled by them.
|
|
291
|
+
useRegisterPaneScrollBox(scrollRef, { enabled: true });
|
|
287
292
|
|
|
288
293
|
useEffect(() => {
|
|
289
294
|
headerHorizontal.bar.visible = false;
|
|
@@ -88,6 +88,20 @@ const ICONS: Record<IconName, ReactNode> = {
|
|
|
88
88
|
<path d="M2 9.1 4.7 6.6l1.6 1.5 1.8-2 2.4 2.5" stroke="currentColor" strokeWidth="1.1" strokeLinecap="round" strokeLinejoin="round" />
|
|
89
89
|
</>
|
|
90
90
|
),
|
|
91
|
+
// A hand with the thumb raised, on the 24-unit grid; the thumbs down is the
|
|
92
|
+
// same hand turned over.
|
|
93
|
+
"thumbs-up": (
|
|
94
|
+
<g transform="scale(0.5)">
|
|
95
|
+
<rect x="3" y="10" width="4" height="10" rx="1" stroke="currentColor" strokeWidth="1.8" strokeLinejoin="round" />
|
|
96
|
+
<path d="M7 10l3.5-6.5a1.8 1.8 0 0 1 3.3 1.2L13 9.5h5.6a2 2 0 0 1 2 2.4l-1.4 6.5a2 2 0 0 1-2 1.6H7" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" />
|
|
97
|
+
</g>
|
|
98
|
+
),
|
|
99
|
+
"thumbs-down": (
|
|
100
|
+
<g transform="scale(0.5) rotate(180 12 12)">
|
|
101
|
+
<rect x="3" y="10" width="4" height="10" rx="1" stroke="currentColor" strokeWidth="1.8" strokeLinejoin="round" />
|
|
102
|
+
<path d="M7 10l3.5-6.5a1.8 1.8 0 0 1 3.3 1.2L13 9.5h5.6a2 2 0 0 1 2 2.4l-1.4 6.5a2 2 0 0 1-2 1.6H7" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" />
|
|
103
|
+
</g>
|
|
104
|
+
),
|
|
91
105
|
restore: (
|
|
92
106
|
<>
|
|
93
107
|
<rect x="2" y="4" width="6" height="6" rx="0.8" stroke="currentColor" strokeWidth="1.1" />
|
|
@@ -10,6 +10,53 @@ import { WebIcon } from "./icons";
|
|
|
10
10
|
|
|
11
11
|
/** Input width of a text filter that names none, in cells (the terminal's default). */
|
|
12
12
|
const DEFAULT_TEXT_FIELD_CELLS = 20;
|
|
13
|
+
/** Beyond this many choices an inline filter is a strip that scrolls by itself, as the terminal's does. */
|
|
14
|
+
const STRIP_OPTION_LIMIT = 6;
|
|
15
|
+
|
|
16
|
+
function isStrip(item: HostQueryBarItem): boolean {
|
|
17
|
+
return item.kind === "select" && item.inline === true && item.options.length > STRIP_OPTION_LIMIT;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The choices of an inline filter. A long one (expiries, chart ranges) is a
|
|
22
|
+
* strip that scrolls on its own, so the label and the controls beside it stay
|
|
23
|
+
* in view while it brings the chosen one into view.
|
|
24
|
+
*/
|
|
25
|
+
function InlineChoices({ item }: { item: HostQueryBarItem }) {
|
|
26
|
+
const stripRef = useRef<HTMLDivElement | null>(null);
|
|
27
|
+
const strip = isStrip(item);
|
|
28
|
+
const overflow = useHorizontalOverflow(stripRef, [item.options.length, strip]);
|
|
29
|
+
return (
|
|
30
|
+
<div className="gloom-qb-inline" data-item-id={item.id} data-narrowing={item.narrowing ? "true" : undefined}
|
|
31
|
+
data-strip={strip ? "true" : undefined}>
|
|
32
|
+
<span className="gloom-qb-label">{item.label}</span>
|
|
33
|
+
<div
|
|
34
|
+
ref={stripRef}
|
|
35
|
+
className="gloom-qb-view gloom-qb-segments"
|
|
36
|
+
role="radiogroup"
|
|
37
|
+
aria-label={item.label}
|
|
38
|
+
style={strip ? overflow.maskStyle : undefined}
|
|
39
|
+
onWheel={strip ? overflow.onWheel : undefined}
|
|
40
|
+
>
|
|
41
|
+
{item.options.map((option) => (
|
|
42
|
+
<button
|
|
43
|
+
key={option.value}
|
|
44
|
+
type="button"
|
|
45
|
+
role="radio"
|
|
46
|
+
aria-checked={option.selected}
|
|
47
|
+
disabled={option.disabled}
|
|
48
|
+
title={option.hint ? `${option.label} (${option.hint})` : undefined}
|
|
49
|
+
data-active={option.selected ? "true" : undefined}
|
|
50
|
+
onMouseDown={(event) => event.stopPropagation()}
|
|
51
|
+
onClick={() => item.onSelect(option.value)}
|
|
52
|
+
>
|
|
53
|
+
<span className="gloom-qb-text">{option.label}</span>
|
|
54
|
+
</button>
|
|
55
|
+
))}
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
13
60
|
|
|
14
61
|
function Chevron() {
|
|
15
62
|
return <span className="gloom-qb-chevron"><WebIcon name="chevron-down" size={9} /></span>;
|
|
@@ -87,30 +134,7 @@ function FilterChip({ item, open, onOpenChange }: { item: HostQueryBarItem; open
|
|
|
87
134
|
useEffect(() => {
|
|
88
135
|
if (open) triggerRef.current?.scrollIntoView({ block: "nearest", inline: "nearest" });
|
|
89
136
|
}, [open]);
|
|
90
|
-
if (item.kind === "select" && item.inline) {
|
|
91
|
-
return (
|
|
92
|
-
<div className="gloom-qb-inline" data-item-id={item.id} data-narrowing={item.narrowing ? "true" : undefined}>
|
|
93
|
-
<span className="gloom-qb-label">{item.label}</span>
|
|
94
|
-
<div className="gloom-qb-view gloom-qb-segments" role="radiogroup" aria-label={item.label}>
|
|
95
|
-
{item.options.map((option) => (
|
|
96
|
-
<button
|
|
97
|
-
key={option.value}
|
|
98
|
-
type="button"
|
|
99
|
-
role="radio"
|
|
100
|
-
aria-checked={option.selected}
|
|
101
|
-
disabled={option.disabled}
|
|
102
|
-
title={option.hint ? `${option.label} (${option.hint})` : undefined}
|
|
103
|
-
data-active={option.selected ? "true" : undefined}
|
|
104
|
-
onMouseDown={(event) => event.stopPropagation()}
|
|
105
|
-
onClick={() => item.onSelect(option.value)}
|
|
106
|
-
>
|
|
107
|
-
<span className="gloom-qb-text">{option.label}</span>
|
|
108
|
-
</button>
|
|
109
|
-
))}
|
|
110
|
-
</div>
|
|
111
|
-
</div>
|
|
112
|
-
);
|
|
113
|
-
}
|
|
137
|
+
if (item.kind === "select" && item.inline) return <InlineChoices item={item} />;
|
|
114
138
|
if (item.kind === "toggle") {
|
|
115
139
|
return (
|
|
116
140
|
<button
|
|
@@ -190,27 +214,30 @@ export function WebQueryBar({ search, items, view, onClearAll, meta, openRequest
|
|
|
190
214
|
const overflow = useHorizontalOverflow(scrollRef, [items.length, !!search, !!view, !!onClearAll, meta]);
|
|
191
215
|
const searchRef = useRef<HTMLDivElement | null>(null);
|
|
192
216
|
// When an inline choice or the view changes (a shortcut, the next expiry),
|
|
193
|
-
// bring the new selection into a scrolled bar.
|
|
194
|
-
//
|
|
217
|
+
// bring the new selection into a scrolled bar. On mount only a strip that
|
|
218
|
+
// scrolls by itself shows its choice: an expiry chosen far down the strip
|
|
219
|
+
// is what the pane shows, but scrolling the whole bar to a view at the right
|
|
220
|
+
// edge would hide the search when the pane opens.
|
|
195
221
|
const selectionKey = [
|
|
196
222
|
...items.filter((item) => item.inline).map((item) => `${item.id}=${item.options.find((option) => option.selected)?.value ?? ""}`),
|
|
197
223
|
`view=${view?.value ?? ""}`,
|
|
198
224
|
].join("|");
|
|
199
|
-
const previousSelectionKey = useRef(
|
|
225
|
+
const previousSelectionKey = useRef<string | null>(null);
|
|
200
226
|
useEffect(() => {
|
|
201
227
|
const previous = previousSelectionKey.current;
|
|
202
228
|
previousSelectionKey.current = selectionKey;
|
|
203
229
|
if (previous === selectionKey) return;
|
|
204
|
-
const before = new Map(previous.split("|").map((entry) => entry.split("=") as [string, string]));
|
|
230
|
+
const before = previous == null ? null : new Map(previous.split("|").map((entry) => entry.split("=") as [string, string]));
|
|
205
231
|
const bar = scrollRef.current;
|
|
206
232
|
if (!bar) return;
|
|
207
233
|
for (const entry of selectionKey.split("|")) {
|
|
208
234
|
const [id, value] = entry.split("=") as [string, string];
|
|
209
|
-
if (before
|
|
235
|
+
if (before?.get(id) === value) continue;
|
|
210
236
|
const group = id === "view"
|
|
211
237
|
? bar.querySelector(":scope > .gloom-qb-view")
|
|
212
|
-
: bar.
|
|
213
|
-
group?.
|
|
238
|
+
: [...bar.querySelectorAll("[data-item-id]")].find((item) => item.getAttribute("data-item-id") === id);
|
|
239
|
+
if (!before && group?.getAttribute("data-strip") !== "true") continue;
|
|
240
|
+
group?.querySelector<HTMLElement>("button[data-active=true]")?.scrollIntoView?.({ block: "nearest", inline: "nearest" });
|
|
214
241
|
}
|
|
215
242
|
}, [selectionKey]);
|
|
216
243
|
useEffect(() => {
|
|
@@ -280,7 +307,7 @@ export function WebQueryBar({ search, items, view, onClearAll, meta, openRequest
|
|
|
280
307
|
)}
|
|
281
308
|
{searchNode}
|
|
282
309
|
{items.length > 0 && (
|
|
283
|
-
<div className="gloom-qb-filters">
|
|
310
|
+
<div className="gloom-qb-filters" data-strip={items.some(isStrip) ? "true" : undefined}>
|
|
284
311
|
{items.map((item) => (
|
|
285
312
|
<FilterChip key={item.id} item={item} open={openId === item.id} onOpenChange={(open) => setOpen(item.id, open)} />
|
|
286
313
|
))}
|