gloomberb 0.16.3 → 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/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/commands/crypto-hints.ts +12 -4
- package/src/cli/commands/market.ts +359 -99
- package/src/cli/commands/options-chain.ts +172 -0
- package/src/cli/commands/options-leaps.ts +422 -0
- package/src/cli/commands/overview.ts +164 -26
- 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 +62 -30
- package/src/cli/desktop-pane-shot.ts +97 -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 +14 -1
- package/src/cli/index-roots.ts +51 -0
- package/src/cli/index.ts +9 -6
- package/src/cli/listing-arg.ts +211 -3
- package/src/cli/not-a-ticker.ts +37 -0
- package/src/cli/options.ts +50 -6
- package/src/cli/pane-functions/capabilities.ts +8 -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 +21 -13
- package/src/cli/pane-functions/freshness.ts +205 -26
- package/src/cli/pane-functions/function-help.ts +67 -22
- package/src/cli/pane-functions/headless.ts +5 -4
- package/src/cli/pane-functions/index.ts +3 -0
- 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 +4 -0
- package/src/cli/pane-functions/resolver.ts +4 -6
- package/src/cli/pane-functions/screenshot-evidence.ts +2 -0
- package/src/cli/pane-functions/screenshot.ts +105 -23
- package/src/cli/registry.ts +2 -1
- package/src/cli/result.ts +50 -13
- 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/view.tsx +28 -9
- 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 +1 -1
- package/src/components/layout/shell/drag/index.ts +4 -0
- package/src/components/layout/shell/drag/live.ts +76 -5
- package/src/components/layout/shell/drag/runtime.ts +8 -8
- package/src/components/layout/shell/index.tsx +47 -6
- package/src/components/layout/shell/layout-state.ts +5 -11
- package/src/components/layout/shell/menu.ts +28 -1
- package/src/components/layout/shell/pane/actions.ts +2 -1
- package/src/components/layout/shell/pane/layers.tsx +51 -10
- 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/visible-layout.ts +44 -1
- 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/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 +118 -18
- 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/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/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/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/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-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/headless.ts +6 -1
- package/src/plugins/builtin/holders/pane.tsx +3 -0
- 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 +109 -39
- 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/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/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/cli/portfolio-command.ts +71 -36
- package/src/plugins/builtin/portfolio-list/cli/render.ts +87 -18
- package/src/plugins/builtin/portfolio-list/cli/shared.ts +2 -16
- package/src/plugins/builtin/portfolio-list/headless.ts +38 -7
- 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/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/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 +4 -4
- 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/supply-chain/model.ts +1 -1
- package/src/plugins/builtin/ticker-detail/headless.ts +43 -21
- 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/geo-series.ts +1 -1
- package/src/plugins/builtin/world-venue-map/index.ts +1 -1
- 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/dom/desktop/icons.tsx +14 -0
- package/src/renderers/dom/desktop/query-bar.tsx +59 -32
- package/src/renderers/dom/host/box.tsx +1 -1
- package/src/renderers/dom/host/drag-shield.ts +17 -6
- package/src/renderers/dom/host/live-frame.ts +10 -2
- package/src/renderers/dom/input-host.tsx +6 -1
- package/src/renderers/dom/styles.css +13 -0
- package/src/renderers/electrobun/bun/desktop/backend.ts +5 -1
- package/src/renderers/electrobun/bun/desktop/detached-windows.ts +12 -1
- package/src/renderers/electrobun/bun/desktop/initialization.ts +2 -1
- package/src/renderers/electrobun/shared/protocol.ts +2 -0
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -1
- package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +101 -5
- package/src/renderers/electrobun/view/main.tsx +4 -1
- package/src/renderers/opentui/input-host.tsx +6 -1
- package/src/renderers/opentui/start.tsx +9 -0
- package/src/shares/portable-layout.ts +16 -6
- package/src/sources/gloomberb-cloud/index.ts +19 -10
- package/src/sources/gloomberb-cloud/normalizers.ts +4 -1
- package/src/sources/listing-symbols.ts +11 -5
- package/src/sources/provider-errors.ts +88 -3
- package/src/sources/provider-router/cached-routes.ts +8 -4
- package/src/sources/provider-router/financial-routes.ts +11 -5
- package/src/sources/provider-router/financials.ts +42 -15
- 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 +23 -5
- package/src/sources/sec-edgar.ts +68 -8
- 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/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/resolve.ts +1 -14
- package/src/types/config.ts +61 -1
- 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 +8 -4
- package/src/ui/index.tsx +2 -0
- package/src/utils/cli-output.ts +14 -1
- package/src/utils/exchanges.ts +13 -0
- package/src/utils/format.ts +2 -1
- package/src/utils/fx-market-hours.ts +34 -0
- package/src/utils/option-expiry.ts +126 -0
- 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
|
@@ -1,13 +1,19 @@
|
|
|
1
|
-
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
1
|
+
import { useCallback, useEffect, useMemo, useRef, useState, type RefObject } from "react";
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
Button,
|
|
5
|
+
ChoiceDialog,
|
|
5
6
|
confirmDialog,
|
|
7
|
+
DetailScrollBody,
|
|
6
8
|
DataTableStackView,
|
|
7
9
|
EmptyState,
|
|
8
10
|
KeyValueRow,
|
|
11
|
+
openUrl,
|
|
9
12
|
PaneStatusBody,
|
|
10
13
|
QueryBar,
|
|
14
|
+
RemoteImage,
|
|
15
|
+
Section,
|
|
16
|
+
SectionHeading,
|
|
11
17
|
useExternalLinkFooter,
|
|
12
18
|
useQueryBarSearch,
|
|
13
19
|
type DataTableCell,
|
|
@@ -18,20 +24,33 @@ import {
|
|
|
18
24
|
import { loadingErrorFooterInfo } from "../../../components/data-table/table-pane";
|
|
19
25
|
import { colors } from "../../../theme/colors";
|
|
20
26
|
import type { PaneProps } from "../../../types/plugin";
|
|
21
|
-
import { Box, ScrollBox, Text, TextAttributes } from "../../../ui";
|
|
22
|
-
import { useDialog } from "../../../ui/dialog";
|
|
27
|
+
import { Box, ScrollBox, Text, TextAttributes, useUiCapabilities, type ScrollBoxRenderable } from "../../../ui";
|
|
28
|
+
import { useDialog, type PromptContext } from "../../../ui/dialog";
|
|
23
29
|
import { isPlainKeyboardEvent } from "../../../utils/keyboard";
|
|
24
30
|
import { formatRelativeAge } from "../../../utils/datetime-format";
|
|
25
31
|
import { requiredGloomberb } from "../../../utils/semver";
|
|
26
32
|
import { VERSION } from "../../../version";
|
|
27
33
|
import { getCurrentPluginTarget, runsExternalPlugins } from "../../current-target";
|
|
28
34
|
import { pluginSetupCommandId } from "../../registry/setup-command";
|
|
35
|
+
import { useAppSelector } from "../../../state/app/context";
|
|
36
|
+
import { BUILTIN_EDITORIAL } from "../../builtin-editorial";
|
|
29
37
|
import { usePluginAppActions, usePluginPaneState } from "../../runtime";
|
|
30
38
|
import { DEBUG_LOG_TEMPLATE_ID } from "../debug/template";
|
|
31
39
|
import { loadRegistry, registryPluginUrl } from "./feed";
|
|
40
|
+
import { highlightedCodes, pluginFunctions, proFunctionCount, type PluginFunction } from "../../plugin-functions";
|
|
41
|
+
import {
|
|
42
|
+
matchingPack,
|
|
43
|
+
packChange,
|
|
44
|
+
packToggles,
|
|
45
|
+
restoreToggles,
|
|
46
|
+
STARTER_PACKS,
|
|
47
|
+
type PackChange,
|
|
48
|
+
type StarterPack,
|
|
49
|
+
} from "./packs";
|
|
32
50
|
import {
|
|
33
51
|
buildRows,
|
|
34
52
|
collectCategories,
|
|
53
|
+
CORE_PLUGIN_ID,
|
|
35
54
|
filterEntries,
|
|
36
55
|
hasUpdate,
|
|
37
56
|
installConsent,
|
|
@@ -54,7 +73,7 @@ import { getMarketplaceHost, getPluginManager, type MarketplaceHost } from "./st
|
|
|
54
73
|
|
|
55
74
|
import { PLUGIN_MARKETPLACE_PANE_ID } from "./ids";
|
|
56
75
|
|
|
57
|
-
type Column = DataTableColumn & { id: "name" | "tagline" | "
|
|
76
|
+
type Column = DataTableColumn & { id: "name" | "tagline" | "panes" | "functions" | "pro" | "status" };
|
|
58
77
|
|
|
59
78
|
const ALL_CATEGORIES = "all";
|
|
60
79
|
/** Category ids are lowercase words; these read wrong title-cased. */
|
|
@@ -64,17 +83,61 @@ function categoryLabel(category: string): string {
|
|
|
64
83
|
return CATEGORY_LABELS[category] ?? category.charAt(0).toUpperCase() + category.slice(1);
|
|
65
84
|
}
|
|
66
85
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
86
|
+
/**
|
|
87
|
+
* A row reads as a name, a short line and three chips: how many panes, the
|
|
88
|
+
* codes that open them, and how many of its functions Pro unlocks. Narrow
|
|
89
|
+
* panes give up the Pro count, then the codes. Versions are in the detail;
|
|
90
|
+
* a waiting update shows in the status.
|
|
91
|
+
*/
|
|
92
|
+
function buildColumns(width: number, fit: { functions: number; status: number }): Column[] {
|
|
93
|
+
const nameWidth = Math.min(23, Math.max(14, Math.floor(width * 0.2)));
|
|
94
|
+
// The description takes what the other columns leave; the chips take what they need.
|
|
70
95
|
return [
|
|
71
96
|
{ id: "name", label: "PLUGIN", width: nameWidth, align: "left" },
|
|
72
97
|
{ id: "tagline", label: "DESCRIPTION", width: 16, align: "left", flexGrow: 1 },
|
|
73
|
-
{ id: "
|
|
74
|
-
{ id: "
|
|
98
|
+
{ id: "panes", label: "PANES", width: 5, align: "right" },
|
|
99
|
+
...(width >= 80 ? [{ id: "functions" as const, label: "FUNCTIONS", width: fit.functions, align: "left" as const }] : []),
|
|
100
|
+
...(width >= 96 ? [{ id: "pro" as const, label: "PRO", width: 3, align: "right" as const }] : []),
|
|
101
|
+
{ id: "status", label: "STATUS", width: fit.status, align: "left" },
|
|
75
102
|
];
|
|
76
103
|
}
|
|
77
104
|
|
|
105
|
+
/** What a row's chips say about a plugin. */
|
|
106
|
+
interface EntryFacts {
|
|
107
|
+
panes: number;
|
|
108
|
+
paneNames: string[];
|
|
109
|
+
functions: PluginFunction[];
|
|
110
|
+
/** At most three codes, for the row. */
|
|
111
|
+
codes: string[];
|
|
112
|
+
/** Functions Free cannot fully open. */
|
|
113
|
+
pro: number;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Read from what the plugin registered when it is loaded here, so a built-in
|
|
118
|
+
* reads the way this build has it; from what the feed says otherwise.
|
|
119
|
+
*/
|
|
120
|
+
function entryFacts(entry: MarketplaceEntry, host: MarketplaceHost | null): EntryFacts {
|
|
121
|
+
const live = entry.installed && host && !entry.loadError ? host.contributions(entry.id) : null;
|
|
122
|
+
const functions = live
|
|
123
|
+
? pluginFunctions({ templates: live.templates, commands: live.commands })
|
|
124
|
+
: (entry.contributes?.shortcuts ?? []).map((shortcut) => ({
|
|
125
|
+
code: shortcut.code,
|
|
126
|
+
name: shortcut.name,
|
|
127
|
+
description: shortcut.description,
|
|
128
|
+
...(shortcut.access ? { access: shortcut.access } : {}),
|
|
129
|
+
}));
|
|
130
|
+
return {
|
|
131
|
+
panes: live ? live.panes.length : entry.contributes?.panes.length ?? 0,
|
|
132
|
+
paneNames: live ? live.panes.map((pane) => pane.name) : [],
|
|
133
|
+
functions,
|
|
134
|
+
codes: entry.bundled ? highlightedCodes(entry.id, functions) : functions.slice(0, 3).map((fn) => fn.code),
|
|
135
|
+
pro: proFunctionCount(functions),
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const ACCESS_LABELS = { pro: "Pro", preview: "Pro, free preview" } as const;
|
|
140
|
+
|
|
78
141
|
const STATUS_COLORS: Record<MarketplaceStatusKind, string> = {
|
|
79
142
|
failed: colors.negative,
|
|
80
143
|
"needs-restart": colors.warning,
|
|
@@ -83,8 +146,9 @@ const STATUS_COLORS: Record<MarketplaceStatusKind, string> = {
|
|
|
83
146
|
update: colors.textBright,
|
|
84
147
|
"needs-gloomberb": colors.warning,
|
|
85
148
|
errors: colors.warning,
|
|
86
|
-
|
|
87
|
-
|
|
149
|
+
// On is the normal state, so it stays quiet and what is off stands out.
|
|
150
|
+
enabled: colors.textDim,
|
|
151
|
+
disabled: colors.textBright,
|
|
88
152
|
none: colors.textDim,
|
|
89
153
|
};
|
|
90
154
|
|
|
@@ -105,12 +169,23 @@ function renderCell(
|
|
|
105
169
|
column: Column,
|
|
106
170
|
rowState: { selected: boolean },
|
|
107
171
|
busyId: string | null,
|
|
172
|
+
facts: (entry: MarketplaceEntry) => EntryFacts,
|
|
108
173
|
): DataTableCell {
|
|
109
174
|
if (row.type === "header") return { text: "" };
|
|
110
175
|
const { entry } = row;
|
|
111
176
|
const selected = rowState.selected ? colors.selectedText : undefined;
|
|
112
177
|
|
|
113
178
|
switch (column.id) {
|
|
179
|
+
case "panes": {
|
|
180
|
+
const panes = facts(entry).panes;
|
|
181
|
+
return { text: panes > 0 ? String(panes) : "", color: selected ?? colors.textDim };
|
|
182
|
+
}
|
|
183
|
+
case "functions":
|
|
184
|
+
return { text: facts(entry).codes.join(" "), color: selected ?? colors.text };
|
|
185
|
+
case "pro": {
|
|
186
|
+
const pro = facts(entry).pro;
|
|
187
|
+
return { text: pro > 0 ? String(pro) : "", color: selected ?? colors.warning };
|
|
188
|
+
}
|
|
114
189
|
case "name":
|
|
115
190
|
return {
|
|
116
191
|
text: entry.name,
|
|
@@ -119,10 +194,6 @@ function renderCell(
|
|
|
119
194
|
};
|
|
120
195
|
case "tagline":
|
|
121
196
|
return { text: entry.tagline, color: selected ?? colors.textDim };
|
|
122
|
-
case "version": {
|
|
123
|
-
const update = hasUpdate(entry);
|
|
124
|
-
return { text: versionLabel(entry), color: selected ?? (update ? colors.textBright : colors.textDim) };
|
|
125
|
-
}
|
|
126
197
|
case "status": {
|
|
127
198
|
if (busyId === entry.id) return { text: "working", color: selected ?? colors.textDim };
|
|
128
199
|
const status = statusOf(entry);
|
|
@@ -206,6 +277,123 @@ function EntryDetail({ entry, width, host }: { entry: MarketplaceEntry; width: n
|
|
|
206
277
|
);
|
|
207
278
|
}
|
|
208
279
|
|
|
280
|
+
/** gloom.sh keeps a reviewed capture of these functions. */
|
|
281
|
+
function functionShotUrl(code: string): string {
|
|
282
|
+
return `https://gloom.sh/screenshots/fn/${encodeURIComponent(code)}.png`;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* A built-in: what it adds and what Pro opens, function by function. The
|
|
287
|
+
* desktop shows a capture or two; the terminal leaves them to gloom.sh.
|
|
288
|
+
*/
|
|
289
|
+
function BuiltinDetail({ entry, width, facts, scrollRef }: {
|
|
290
|
+
entry: MarketplaceEntry;
|
|
291
|
+
width: number;
|
|
292
|
+
facts: EntryFacts;
|
|
293
|
+
scrollRef: RefObject<ScrollBoxRenderable | null>;
|
|
294
|
+
}) {
|
|
295
|
+
const { nativePaneChrome } = useUiCapabilities();
|
|
296
|
+
// DetailScrollBody pads a cell on each side, and its scrollbar takes one.
|
|
297
|
+
const rowWidth = Math.max(1, width - 4);
|
|
298
|
+
const nameWidth = Math.max(12, Math.min(34, rowWidth - 8 - 20));
|
|
299
|
+
const status = statusOf(entry);
|
|
300
|
+
const shots = nativePaneChrome ? (BUILTIN_EDITORIAL[entry.id]?.screenshots ?? []).slice(0, 2) : [];
|
|
301
|
+
const shotWidth = Math.min(rowWidth, 72);
|
|
302
|
+
const summary = [
|
|
303
|
+
`${facts.panes} pane${facts.panes === 1 ? "" : "s"}`,
|
|
304
|
+
`${facts.functions.length} function${facts.functions.length === 1 ? "" : "s"}`,
|
|
305
|
+
...(facts.pro > 0 ? [`${facts.pro} Pro`] : []),
|
|
306
|
+
];
|
|
307
|
+
|
|
308
|
+
return (
|
|
309
|
+
<DetailScrollBody ref={scrollRef} resetScrollKey={entry.id}>
|
|
310
|
+
<Box flexDirection="row" gap={2} height={1}>
|
|
311
|
+
<Text fg={STATUS_COLORS[status.kind]}>{status.text}</Text>
|
|
312
|
+
<Text fg={colors.textDim}>{summary.join(" · ")}</Text>
|
|
313
|
+
</Box>
|
|
314
|
+
|
|
315
|
+
{entry.description ? (
|
|
316
|
+
<Box paddingTop={1} flexDirection="column">
|
|
317
|
+
<Text fg={colors.text}>{entry.description}</Text>
|
|
318
|
+
</Box>
|
|
319
|
+
) : null}
|
|
320
|
+
|
|
321
|
+
{shots.length > 0 ? (
|
|
322
|
+
<Box paddingTop={1} flexDirection="column" gap={1}>
|
|
323
|
+
{shots.map((code) => (
|
|
324
|
+
<RemoteImage
|
|
325
|
+
key={code}
|
|
326
|
+
src={functionShotUrl(code)}
|
|
327
|
+
alt={`${code} in Gloomberb`}
|
|
328
|
+
label={code}
|
|
329
|
+
width={shotWidth}
|
|
330
|
+
height={Math.max(8, Math.floor(shotWidth * 0.3))}
|
|
331
|
+
/>
|
|
332
|
+
))}
|
|
333
|
+
</Box>
|
|
334
|
+
) : null}
|
|
335
|
+
|
|
336
|
+
{facts.functions.length > 0 ? (
|
|
337
|
+
<Section title="Functions" width={rowWidth}>
|
|
338
|
+
{facts.functions.map((fn) => (
|
|
339
|
+
// The code is what people type, so it leads; Pro reads in the PRO column's colour.
|
|
340
|
+
<Box key={fn.code} flexDirection="row" height={1} width={rowWidth} overflow="hidden">
|
|
341
|
+
<Box width={8} flexShrink={0}><Text fg={colors.textBright}>{fn.code}</Text></Box>
|
|
342
|
+
<Box width={nameWidth} flexShrink={0} overflow="hidden"><Text fg={colors.text}>{fn.name}</Text></Box>
|
|
343
|
+
{fn.access ? <Box flexShrink={1} minWidth={0} overflow="hidden"><Text fg={colors.warning}>{ACCESS_LABELS[fn.access]}</Text></Box> : null}
|
|
344
|
+
</Box>
|
|
345
|
+
))}
|
|
346
|
+
</Section>
|
|
347
|
+
) : null}
|
|
348
|
+
|
|
349
|
+
{facts.paneNames.length > 0 ? (
|
|
350
|
+
<Box paddingTop={1} flexDirection="column">
|
|
351
|
+
<SectionHeading title="Panes" width={rowWidth} />
|
|
352
|
+
<Text fg={colors.textDim}>{facts.paneNames.join(", ")}</Text>
|
|
353
|
+
</Box>
|
|
354
|
+
) : null}
|
|
355
|
+
</DetailScrollBody>
|
|
356
|
+
);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/** The strip's labels; the full names are in the menu, the confirmation and the toast. */
|
|
360
|
+
const PACK_SHORT_LABELS: Record<string, string> = {
|
|
361
|
+
everything: "Everything",
|
|
362
|
+
"equity-research": "Equity",
|
|
363
|
+
"options-desk": "Options",
|
|
364
|
+
"macro-rates": "Macro",
|
|
365
|
+
"credit-bonds": "Credit",
|
|
366
|
+
"alt-data-quant": "Alt data",
|
|
367
|
+
};
|
|
368
|
+
/** The strip's value when the plugins on match no pack. */
|
|
369
|
+
const CUSTOM_PACK = "custom";
|
|
370
|
+
|
|
371
|
+
/** One line per kind of change, with the plugins it names. */
|
|
372
|
+
function PackChangeBody({ change, name, width }: { change: PackChange; name: (id: string) => string; width: number }) {
|
|
373
|
+
const lines = [
|
|
374
|
+
{ label: "Turn off", ids: change.turnOff },
|
|
375
|
+
{ label: "Turn on", ids: change.turnOn },
|
|
376
|
+
{ label: "Keep", ids: change.keep },
|
|
377
|
+
].filter((line) => line.ids.length > 0);
|
|
378
|
+
return (
|
|
379
|
+
<Box flexDirection="column" width={width} gap={1}>
|
|
380
|
+
{lines.map((line) => (
|
|
381
|
+
<Box key={line.label} flexDirection="row" width={width}>
|
|
382
|
+
<Box width={12} flexShrink={0}>
|
|
383
|
+
<Text fg={colors.textBright} attributes={TextAttributes.BOLD}>{`${line.label} ${line.ids.length}`}</Text>
|
|
384
|
+
</Box>
|
|
385
|
+
<Box flexGrow={1} flexShrink={1} minWidth={0}>
|
|
386
|
+
<Text fg={colors.text} wrapText>{line.ids.map(name).join(", ")}</Text>
|
|
387
|
+
</Box>
|
|
388
|
+
</Box>
|
|
389
|
+
))}
|
|
390
|
+
{change.turnOff.length > 0 ? (
|
|
391
|
+
<Text fg={colors.textDim} wrapText>Panes are hidden, not closed. Undo brings them back.</Text>
|
|
392
|
+
) : null}
|
|
393
|
+
</Box>
|
|
394
|
+
);
|
|
395
|
+
}
|
|
396
|
+
|
|
209
397
|
type Busy = { id: string; verb: "installing" | "updating" | "removing" } | null;
|
|
210
398
|
|
|
211
399
|
export function PluginMarketplacePane({ focused, width, height }: PaneProps) {
|
|
@@ -213,10 +401,12 @@ export function PluginMarketplacePane({ focused, width, height }: PaneProps) {
|
|
|
213
401
|
const { createPaneFromTemplate, showPane, openPluginCommandWorkflow, notify } = usePluginAppActions();
|
|
214
402
|
const [query, setQuery] = useState("");
|
|
215
403
|
const [category, setCategory] = usePluginPaneState<string | null>("category", null);
|
|
216
|
-
|
|
404
|
+
// Built-ins are what Gloomberb is made of, so they show unless filtered out.
|
|
405
|
+
const [showBuiltin, setShowBuiltin] = usePluginPaneState<boolean>("showBuiltin", true);
|
|
217
406
|
const [selectedId, setSelectedId] = usePluginPaneState<string | null>("selectedId", null);
|
|
218
407
|
const [detailOpen, setDetailOpen] = usePluginPaneState<boolean>("detailOpen", false);
|
|
219
408
|
const { active: searchFocused, focus: focusSearch, blur: blurSearch, searchProps } = useQueryBarSearch();
|
|
409
|
+
const detailScrollRef = useRef<ScrollBoxRenderable | null>(null);
|
|
220
410
|
|
|
221
411
|
const [registry, setRegistry] = useState<RegistryPlugin[]>([]);
|
|
222
412
|
const [status, setStatus] = useState<"loading" | "ready" | "error">("loading");
|
|
@@ -231,12 +421,6 @@ export function PluginMarketplacePane({ focused, width, height }: PaneProps) {
|
|
|
231
421
|
const [remoteHeads, setRemoteHeads] = useState<Record<string, string>>({});
|
|
232
422
|
const [checkingRemotes, setCheckingRemotes] = useState(false);
|
|
233
423
|
const busyId = busy?.id ?? null;
|
|
234
|
-
const renderRow = useCallback((
|
|
235
|
-
row: MarketplaceRow,
|
|
236
|
-
column: Column,
|
|
237
|
-
_index: number,
|
|
238
|
-
rowState: { selected: boolean },
|
|
239
|
-
) => renderCell(row, column, rowState, busyId), [busyId]);
|
|
240
424
|
|
|
241
425
|
const refresh = useCallback((force: boolean) => {
|
|
242
426
|
setStatus((current) => (current === "ready" ? current : "loading"));
|
|
@@ -253,11 +437,32 @@ export function PluginMarketplacePane({ focused, width, height }: PaneProps) {
|
|
|
253
437
|
const host = getMarketplaceHost();
|
|
254
438
|
const manager = getPluginManager();
|
|
255
439
|
const target = getCurrentPluginTarget();
|
|
440
|
+
// A switch from anywhere (a pack, a toast, a sync) re-reads the list.
|
|
441
|
+
const disabledPlugins = useAppSelector((state) => state.config.disabledPlugins);
|
|
256
442
|
const entries = useMemo(() => {
|
|
257
443
|
void localRevision;
|
|
444
|
+
void disabledPlugins;
|
|
258
445
|
const installed = host?.listInstalled() ?? [];
|
|
259
446
|
return sortEntries(mergeCatalog({ registry, installed, target, remoteHeads }));
|
|
260
|
-
}, [host, registry, target, localRevision, remoteHeads]);
|
|
447
|
+
}, [host, registry, target, localRevision, remoteHeads, disabledPlugins]);
|
|
448
|
+
const currentPack = useMemo(() => matchingPack(disabledPlugins), [disabledPlugins]);
|
|
449
|
+
// Rebuilt with the entries, which a switch or an install already refreshes.
|
|
450
|
+
const factsFor = useMemo(() => {
|
|
451
|
+
const cache = new Map<string, EntryFacts>();
|
|
452
|
+
return (entry: MarketplaceEntry): EntryFacts => {
|
|
453
|
+
const cached = cache.get(entry.id);
|
|
454
|
+
if (cached) return cached;
|
|
455
|
+
const facts = entryFacts(entry, host);
|
|
456
|
+
cache.set(entry.id, facts);
|
|
457
|
+
return facts;
|
|
458
|
+
};
|
|
459
|
+
}, [entries, host]);
|
|
460
|
+
const renderRow = useCallback((
|
|
461
|
+
row: MarketplaceRow,
|
|
462
|
+
column: Column,
|
|
463
|
+
_index: number,
|
|
464
|
+
rowState: { selected: boolean },
|
|
465
|
+
) => renderCell(row, column, rowState, busyId, factsFor), [busyId, factsFor]);
|
|
261
466
|
|
|
262
467
|
// Keyed by the folders themselves: the entries array is rebuilt whenever an
|
|
263
468
|
// answer lands, and re-running the check on its own result would never stop.
|
|
@@ -442,11 +647,84 @@ export function PluginMarketplacePane({ focused, width, height }: PaneProps) {
|
|
|
442
647
|
}
|
|
443
648
|
}, [bump, busy, confirmWidth, dialog, host, manager, notify, selected]);
|
|
444
649
|
|
|
445
|
-
const toggleSelected = useCallback(() => {
|
|
650
|
+
const toggleSelected = useCallback(async () => {
|
|
446
651
|
if (!host || !selected || !selected.installed || !selected.toggleable || selected.loadError) return;
|
|
447
|
-
|
|
652
|
+
const entry = selected;
|
|
653
|
+
if (entry.id === CORE_PLUGIN_ID && entry.bundled && entry.enabled) {
|
|
654
|
+
const confirmed = await confirmDialog(dialog, {
|
|
655
|
+
title: `Turn off ${entry.name}?`,
|
|
656
|
+
body: ["DES, G and the research pane stop working until you turn it back on."],
|
|
657
|
+
confirmLabel: "Turn off",
|
|
658
|
+
width: confirmWidth,
|
|
659
|
+
});
|
|
660
|
+
if (!confirmed) return;
|
|
661
|
+
}
|
|
662
|
+
host.setPluginEnabled(entry.id, !entry.enabled);
|
|
663
|
+
bump();
|
|
664
|
+
}, [bump, confirmWidth, dialog, host, selected]);
|
|
665
|
+
|
|
666
|
+
const pluginName = useCallback(
|
|
667
|
+
(id: string) => entries.find((entry) => entry.id === id)?.name ?? id,
|
|
668
|
+
[entries],
|
|
669
|
+
);
|
|
670
|
+
|
|
671
|
+
/**
|
|
672
|
+
* Says exactly what the pack turns off and on, applies it in one switch,
|
|
673
|
+
* and offers Undo: nothing is closed, so the old set comes back as it was.
|
|
674
|
+
*/
|
|
675
|
+
const applyPack = useCallback(async (pack: StarterPack) => {
|
|
676
|
+
if (!host) return;
|
|
677
|
+
const previous = [...disabledPlugins];
|
|
678
|
+
const change = packChange(previous, pack);
|
|
679
|
+
const toggles = packToggles(change);
|
|
680
|
+
if (Object.keys(toggles).length === 0) {
|
|
681
|
+
notify({ body: `${pack.name} is already what you have on.`, type: "info" });
|
|
682
|
+
return;
|
|
683
|
+
}
|
|
684
|
+
const confirmed = await confirmDialog(dialog, {
|
|
685
|
+
title: `Switch to ${pack.name}?`,
|
|
686
|
+
body: <PackChangeBody change={change} name={pluginName} width={confirmWidth} />,
|
|
687
|
+
confirmLabel: "Switch",
|
|
688
|
+
confirmVariant: "primary",
|
|
689
|
+
width: confirmWidth,
|
|
690
|
+
});
|
|
691
|
+
if (!confirmed) return;
|
|
692
|
+
host.setPluginsEnabled(toggles);
|
|
448
693
|
bump();
|
|
449
|
-
|
|
694
|
+
const parts = [
|
|
695
|
+
...(change.turnOff.length > 0 ? [`${change.turnOff.length} off`] : []),
|
|
696
|
+
...(change.turnOn.length > 0 ? [`${change.turnOn.length} back on`] : []),
|
|
697
|
+
];
|
|
698
|
+
notify({
|
|
699
|
+
body: `${pack.name}: ${parts.join(", ")}.`,
|
|
700
|
+
type: "success",
|
|
701
|
+
// Long enough to reach for Undo after looking at the list.
|
|
702
|
+
duration: 12_000,
|
|
703
|
+
action: {
|
|
704
|
+
label: "Undo",
|
|
705
|
+
onClick: () => {
|
|
706
|
+
host.setPluginsEnabled(restoreToggles(previous));
|
|
707
|
+
bump();
|
|
708
|
+
},
|
|
709
|
+
},
|
|
710
|
+
});
|
|
711
|
+
}, [bump, confirmWidth, dialog, disabledPlugins, host, notify, pluginName]);
|
|
712
|
+
|
|
713
|
+
const choosePack = useCallback(async () => {
|
|
714
|
+
const id = await dialog.prompt<string>({
|
|
715
|
+
closeOnClickOutside: true,
|
|
716
|
+
content: (context: PromptContext<string>) => (
|
|
717
|
+
<ChoiceDialog
|
|
718
|
+
{...context}
|
|
719
|
+
title="Starter packs"
|
|
720
|
+
selectedChoiceId={currentPack?.id}
|
|
721
|
+
choices={STARTER_PACKS.map((pack) => ({ id: pack.id, label: pack.name, description: pack.tagline }))}
|
|
722
|
+
/>
|
|
723
|
+
),
|
|
724
|
+
}).catch(() => null);
|
|
725
|
+
const pack = STARTER_PACKS.find((candidate) => candidate.id === id);
|
|
726
|
+
if (pack) await applyPack(pack);
|
|
727
|
+
}, [applyPack, currentPack, dialog]);
|
|
450
728
|
|
|
451
729
|
const setupSelected = useCallback(() => {
|
|
452
730
|
if (!selected || !selected.installed || !selected.hasSetup || !selected.enabled) return;
|
|
@@ -484,7 +762,8 @@ export function PluginMarketplacePane({ focused, width, height }: PaneProps) {
|
|
|
484
762
|
// Not u: that installs an app update whenever one is waiting.
|
|
485
763
|
case "g": void updateSelected(); return true;
|
|
486
764
|
case "x": void removeSelected(); return true;
|
|
487
|
-
case "e": toggleSelected(); return true;
|
|
765
|
+
case "e": void toggleSelected(); return true;
|
|
766
|
+
case "a": void choosePack(); return true;
|
|
488
767
|
case "s": setupSelected(); return true;
|
|
489
768
|
case "p": openSelected(); return true;
|
|
490
769
|
case "d": openLog(); return true;
|
|
@@ -492,7 +771,7 @@ export function PluginMarketplacePane({ focused, width, height }: PaneProps) {
|
|
|
492
771
|
case "b": setShowBuiltin((value) => !value); return true;
|
|
493
772
|
default: return false;
|
|
494
773
|
}
|
|
495
|
-
}, [installSelected, openLog, openSelected, refresh, removeSelected, setupSelected, toggleSelected, updateSelected]);
|
|
774
|
+
}, [choosePack, installSelected, openLog, openSelected, refresh, removeSelected, setShowBuiltin, setupSelected, toggleSelected, updateSelected]);
|
|
496
775
|
|
|
497
776
|
/**
|
|
498
777
|
* Pane keys go through the table's key handler, which runs while the pane
|
|
@@ -542,11 +821,15 @@ export function PluginMarketplacePane({ focused, width, height }: PaneProps) {
|
|
|
542
821
|
? { id: "update", key: "g", label: " reload", title: "Reload", onPress: () => { void updateSelected(); } }
|
|
543
822
|
: { id: "update", key: "g", label: "et update", onPress: () => { void updateSelected(); } });
|
|
544
823
|
}
|
|
545
|
-
if (canToggle) hints.push({ id: "toggle", key: "e", label: selected?.enabled ? "disable" : "nable", title: selected?.enabled ? "Disable" : "Enable", onPress: toggleSelected });
|
|
824
|
+
if (canToggle) hints.push({ id: "toggle", key: "e", label: selected?.enabled ? "disable" : "nable", title: selected?.enabled ? "Disable" : "Enable", onPress: () => { void toggleSelected(); } });
|
|
546
825
|
if (canSetup) hints.push({ id: "setup", key: "s", label: "etup", onPress: setupSelected });
|
|
547
826
|
if (canOpen) hints.push({ id: "open-pane", key: "p", label: "ane", onPress: openSelected });
|
|
548
827
|
if (canLog) hints.push({ id: "log", key: "d", label: "ebug log", onPress: openLog });
|
|
549
828
|
if (canRemove) hints.push({ id: "remove", key: "x", label: " remove", onPress: () => { void removeSelected(); } });
|
|
829
|
+
if (host) hints.push({ id: "packs", key: "a", label: " packs", title: "Starter packs", onPress: () => { void choosePack(); } });
|
|
830
|
+
// A built-in has no repository; its page on gloom.sh shows it at work.
|
|
831
|
+
const seeItUrl = selected?.bundled ? registryPluginUrl(selected.id) : null;
|
|
832
|
+
if (seeItUrl) hints.push({ id: "see-it", key: "o", label: " see it", title: "See it on gloom.sh", onPress: () => openUrl(seeItUrl) });
|
|
550
833
|
|
|
551
834
|
useExternalLinkFooter({
|
|
552
835
|
registrationId: PLUGIN_MARKETPLACE_PANE_ID,
|
|
@@ -557,7 +840,15 @@ export function PluginMarketplacePane({ focused, width, height }: PaneProps) {
|
|
|
557
840
|
hints,
|
|
558
841
|
});
|
|
559
842
|
|
|
560
|
-
const
|
|
843
|
+
const fit = useMemo(() => ({
|
|
844
|
+
functions: Math.min(16, Math.max(9, ...visible.map((entry) => factsFor(entry).codes.join(" ").length))),
|
|
845
|
+
status: Math.min(14, Math.max(7, ...visible.map((entry) => statusOf(entry).text.length))),
|
|
846
|
+
}), [factsFor, visible]);
|
|
847
|
+
const columns = useMemo(() => buildColumns(width, fit), [fit, width]);
|
|
848
|
+
const packOptions = useMemo(() => [
|
|
849
|
+
...STARTER_PACKS.map((pack) => ({ value: pack.id, label: pack.name, short: PACK_SHORT_LABELS[pack.id], description: pack.tagline })),
|
|
850
|
+
...(currentPack ? [] : [{ value: CUSTOM_PACK, label: "Custom", description: "Your own set of plugins.", disabled: true }]),
|
|
851
|
+
], [currentPack]);
|
|
561
852
|
// The pick is saved with the pane, so keep it listed (and resettable) even
|
|
562
853
|
// when the catalog no longer has plugins in it.
|
|
563
854
|
const categoryOptions = useMemo(
|
|
@@ -599,10 +890,30 @@ export function PluginMarketplacePane({ focused, width, height }: PaneProps) {
|
|
|
599
890
|
<DataTableStackView<MarketplaceRow, Column>
|
|
600
891
|
focused={focused && !searchFocused}
|
|
601
892
|
detailOpen={detailOpen && !!selected}
|
|
893
|
+
detailScrollRef={selected?.bundled ? detailScrollRef : undefined}
|
|
602
894
|
onBack={() => setDetailOpen(false)}
|
|
603
|
-
detailContent={selected
|
|
895
|
+
detailContent={selected
|
|
896
|
+
? selected.bundled
|
|
897
|
+
? <BuiltinDetail entry={selected} width={width} facts={factsFor(selected)} scrollRef={detailScrollRef} />
|
|
898
|
+
: <EntryDetail entry={selected} width={width} host={host} />
|
|
899
|
+
: null}
|
|
604
900
|
detailTitle={selected?.name}
|
|
605
901
|
rootBefore={(
|
|
902
|
+
<Box flexDirection="column" flexShrink={0}>
|
|
903
|
+
<QueryBar
|
|
904
|
+
width={width}
|
|
905
|
+
filters={[{
|
|
906
|
+
id: "pack",
|
|
907
|
+
label: "Starter pack",
|
|
908
|
+
inline: true,
|
|
909
|
+
value: currentPack?.id ?? CUSTOM_PACK,
|
|
910
|
+
options: packOptions,
|
|
911
|
+
onChange: (value: string) => {
|
|
912
|
+
const pack = STARTER_PACKS.find((candidate) => candidate.id === value);
|
|
913
|
+
if (pack) void applyPack(pack);
|
|
914
|
+
},
|
|
915
|
+
}]}
|
|
916
|
+
/>
|
|
606
917
|
<QueryBar
|
|
607
918
|
width={width}
|
|
608
919
|
search={{
|
|
@@ -621,9 +932,10 @@ export function PluginMarketplacePane({ focused, width, height }: PaneProps) {
|
|
|
621
932
|
options: categoryOptions,
|
|
622
933
|
onChange: (value: string) => setCategory(value === ALL_CATEGORIES ? null : value),
|
|
623
934
|
}] : []),
|
|
624
|
-
{ kind: "toggle" as const, id: "builtin", label: "Built in", value: showBuiltin, onChange: setShowBuiltin },
|
|
935
|
+
{ kind: "toggle" as const, id: "builtin", label: "Built in", value: showBuiltin, defaultValue: true, onChange: setShowBuiltin },
|
|
625
936
|
]}
|
|
626
937
|
/>
|
|
938
|
+
</Box>
|
|
627
939
|
)}
|
|
628
940
|
selection={{
|
|
629
941
|
kind: "id",
|
|
@@ -14,6 +14,12 @@ import type { InstalledPlugin } from "./model";
|
|
|
14
14
|
export interface MarketplaceHost {
|
|
15
15
|
listInstalled(): InstalledPlugin[];
|
|
16
16
|
setPluginEnabled(pluginId: string, enabled: boolean): void;
|
|
17
|
+
/**
|
|
18
|
+
* Switches several plugins as one change, the way a starter pack does. A
|
|
19
|
+
* switched-off plugin's panes are hidden, not closed, so switching it back
|
|
20
|
+
* on shows them where they were.
|
|
21
|
+
*/
|
|
22
|
+
setPluginsEnabled(changes: Readonly<Record<string, boolean>>): void;
|
|
17
23
|
/**
|
|
18
24
|
* Registers a plugin that was loaded after startup, so its panes and
|
|
19
25
|
* commands exist in this session. Replaces a previous registration of the
|
|
@@ -37,7 +43,7 @@ export interface MarketplaceHost {
|
|
|
37
43
|
interface PluginContributions {
|
|
38
44
|
panes: Array<{ id: string; name: string }>;
|
|
39
45
|
templates: Array<{ id: string; label: string; prefix?: string }>;
|
|
40
|
-
commands: Array<{ id: string; label: string }>;
|
|
46
|
+
commands: Array<{ id: string; label: string; shortcut?: string }>;
|
|
41
47
|
capabilities: number;
|
|
42
48
|
broker: boolean;
|
|
43
49
|
}
|