gloomberb 0.11.0 → 0.11.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -15
- package/README.zh-CN.md +12 -12
- package/package.json +10 -3
- package/src/api-client/auth.ts +14 -10
- package/src/api-client/data.ts +54 -0
- package/src/api-client/index.test.ts +124 -0
- package/src/api-client/index.ts +139 -4
- package/src/api-client/paths.ts +89 -0
- package/src/api-client/request.ts +15 -2
- package/src/api-client/socket-health.test.ts +1 -0
- package/src/api-client/socket.ts +2 -1
- package/src/api-client/types.ts +163 -0
- package/src/app/pane-runtime/index.tsx +4 -1
- package/src/app/pane-runtime/plugin-bindings.test.ts +117 -0
- package/src/app/pane-runtime/plugin-bindings.ts +25 -4
- package/src/app/pane-runtime/ticker-inspector-runtime.ts +25 -14
- package/src/app/runtime/desktop-deeplink.test.ts +16 -0
- package/src/app/runtime/desktop-deeplink.ts +66 -2
- package/src/app/runtime/desktop-menu.ts +3 -0
- package/src/app/runtime/plugin-bindings.ts +30 -28
- package/src/app/runtime/update.ts +8 -6
- package/src/app.tsx +21 -7
- package/src/architecture/import-boundaries.test.ts +5 -1
- package/src/capabilities/factories.ts +4 -0
- package/src/cli/commands/automation.test.ts +9 -0
- package/src/cli/commands/automation.ts +22 -73
- package/src/cli/index.ts +10 -6
- package/src/cli/registry.ts +1 -1
- package/src/components/chart/composite/composite-chart.test.tsx +45 -2
- package/src/components/chart/composite/composite-chart.tsx +16 -12
- package/src/components/chart/composite/format.test.ts +34 -0
- package/src/components/chart/composite/format.ts +33 -10
- package/src/components/chart/composite/scene.ts +0 -21
- package/src/components/chart/composite/tools.ts +49 -0
- package/src/components/chart/core/axis-format.ts +13 -3
- package/src/components/chart/core/index.test.ts +7 -0
- package/src/components/chart/core/renderer.ts +3 -4
- package/src/components/command-bar/commands/direct/index.ts +4 -0
- package/src/components/command-bar/commands/registry.ts +8 -1
- package/src/components/command-bar/layout-items/current-layout.ts +1 -1
- package/src/components/command-bar/pane-templates/workflow.ts +4 -0
- package/src/components/command-bar/routes/root/shortcut-feedback.ts +3 -0
- package/src/components/command-bar/routes/root/shortcuts.test.ts +19 -0
- package/src/components/command-bar/routes/root/shortcuts.ts +3 -1
- package/src/components/command-bar/surface/index.test.tsx +6 -6
- package/src/components/command-bar/surface/index.tsx +4 -1
- package/src/components/command-bar/surface/pane.test.tsx +66 -2
- package/src/components/command-bar/view-model.test.ts +2 -1
- package/src/components/command-bar/workflow/ops.test.ts +54 -0
- package/src/components/command-bar/workflow/ops.ts +1 -1
- package/src/components/company-logo.test.ts +19 -0
- package/src/components/company-logo.tsx +60 -0
- package/src/components/feed-data-table/stack-view.tsx +7 -1
- package/src/components/index.ts +1 -0
- package/src/components/layout/detached-pane-shell.tsx +85 -15
- package/src/components/layout/header.tsx +5 -5
- package/src/components/layout/pane/title.ts +31 -3
- package/src/components/layout/shell/active-drag.ts +4 -11
- package/src/components/layout/shell/drag/index.ts +4 -20
- package/src/components/layout/shell/drag/runtime.ts +3 -4
- package/src/components/layout/shell/index.test.tsx +17 -3
- package/src/components/layout/shell/index.tsx +89 -31
- package/src/components/layout/shell/menu.test.ts +37 -1
- package/src/components/layout/shell/menu.ts +14 -0
- package/src/components/layout/shell/native/pointer-runtime.ts +22 -8
- package/src/components/layout/shell/pane/actions.ts +0 -5
- package/src/components/layout/shell/pane/management-shortcuts.ts +9 -4
- package/src/components/layout/shell/shortcuts.ts +6 -3
- package/src/components/layout/shell/ticker-link-menu.test.ts +82 -0
- package/src/components/layout/shell/ticker-link-menu.ts +78 -0
- package/src/components/layout/status-bar.test.tsx +62 -61
- package/src/components/layout/status-bar.tsx +53 -75
- package/src/components/onboarding/account-step/form-panel.tsx +4 -2
- package/src/components/onboarding/account-step/index.tsx +1 -1
- package/src/components/onboarding/account-step/signed-in-panel.tsx +1 -1
- package/src/components/onboarding/onboarding-wizard.test.tsx +44 -1
- package/src/components/onboarding/onboarding-wizard.tsx +13 -5
- package/src/components/onboarding/wizard-account.ts +4 -23
- package/src/components/table-view-shared.test.ts +11 -0
- package/src/components/table-view-shared.tsx +26 -0
- package/src/components/ui/data-table/index.tsx +19 -1
- package/src/components/ui/fields.tsx +5 -1
- package/src/core/state/app/layout-reducer.ts +36 -0
- package/src/core/state/app/layout.ts +10 -5
- package/src/core/state/app/state.ts +0 -13
- package/src/core/state/app/types.ts +6 -4
- package/src/data/config/chart-settings.ts +1 -1
- package/src/data/config/layout.ts +2 -0
- package/src/data/config/store/index.test.ts +27 -6
- package/src/data/config/store/normalize.ts +3 -5
- package/src/data/plugin-state-store.ts +11 -0
- package/src/data/sqlite/cache.test.ts +10 -0
- package/src/i18n/es.ts +13 -5
- package/src/i18n/ja.ts +13 -5
- package/src/i18n/ko.ts +13 -5
- package/src/i18n/zh-cn.ts +13 -5
- package/src/i18n/zh-tw.ts +13 -5
- package/src/layout-marketplace/api.test.ts +54 -0
- package/src/layout-marketplace/api.ts +65 -0
- package/src/layout-marketplace/gallery-desktop.test.tsx +262 -0
- package/src/layout-marketplace/gallery-desktop.tsx +375 -0
- package/src/layout-marketplace/gallery-terminal.tsx +376 -0
- package/src/layout-marketplace/gallery.test.tsx +84 -0
- package/src/layout-marketplace/gallery.tsx +323 -0
- package/src/layout-marketplace/geometry.test.ts +47 -0
- package/src/layout-marketplace/geometry.ts +80 -0
- package/src/layout-marketplace/mini-workspace.test.tsx +122 -0
- package/src/layout-marketplace/mini-workspace.tsx +428 -0
- package/src/layout-marketplace/model.test.ts +118 -0
- package/src/layout-marketplace/model.ts +171 -0
- package/src/layout-marketplace/name-dialog.tsx +60 -0
- package/src/layout-marketplace/pane-imagery.ts +85 -0
- package/src/layout-marketplace/pane.tsx +20 -0
- package/src/layout-marketplace/payload.test.ts +246 -0
- package/src/layout-marketplace/payload.ts +624 -0
- package/src/layout-marketplace/use-marketplace.ts +63 -0
- package/src/market-data/coordinator/index.test.ts +2 -2
- package/src/market-data/coordinator/index.ts +1 -1
- package/src/market-data/hooks.tsx +0 -41
- package/src/market-data/market/format.test.ts +7 -0
- package/src/market-data/market/freshness.ts +5 -2
- package/src/market-data/quotes/freshness.test.ts +16 -0
- package/src/news/aggregator.test.ts +92 -3
- package/src/news/aggregator.ts +98 -18
- package/src/news/hooks.test.tsx +2 -0
- package/src/news/hooks.ts +27 -1
- package/src/news/news-model.ts +5 -2
- package/src/news/types.ts +7 -0
- package/src/plugins/broker-sync/broker-sync.test.ts +58 -0
- package/src/plugins/broker-sync/normalize.ts +42 -5
- package/src/plugins/builtin/account-management/pane.tsx +5 -5
- package/src/plugins/builtin/ai/index.tsx +18 -2
- package/src/plugins/builtin/ai/screener/pane.test.tsx +47 -4
- package/src/plugins/builtin/ai/screener/pane.tsx +35 -12
- package/src/plugins/builtin/alerts/alert-engine.test.ts +53 -1
- package/src/plugins/builtin/alerts/alert-engine.ts +34 -1
- package/src/plugins/builtin/alerts/index.test.tsx +49 -6
- package/src/plugins/builtin/alerts/index.tsx +11 -6
- package/src/plugins/builtin/alerts/pane.tsx +51 -9
- package/src/plugins/builtin/alerts/quotes.ts +11 -3
- package/src/plugins/builtin/alerts/types.ts +1 -0
- package/src/plugins/builtin/analytics/index.tsx +11 -1
- package/src/plugins/builtin/analytics/pane-model.ts +6 -4
- package/src/plugins/builtin/broker-manager/index.tsx +3 -0
- package/src/plugins/builtin/buildout/model/index.ts +1 -1
- package/src/plugins/builtin/buildout/pane/index.tsx +17 -18
- package/src/plugins/builtin/cds/client.test.ts +83 -0
- package/src/plugins/builtin/cds/client.ts +67 -0
- package/src/plugins/builtin/cds/index.tsx +41 -0
- package/src/plugins/builtin/cds/model.test.ts +232 -0
- package/src/plugins/builtin/cds/model.ts +401 -0
- package/src/plugins/builtin/cds/pane.test.tsx +132 -0
- package/src/plugins/builtin/cds/pane.tsx +358 -0
- package/src/plugins/builtin/chart-composer/chart-spec.ts +31 -0
- package/src/plugins/builtin/chart-composer/index.tsx +88 -2
- package/src/plugins/builtin/chart-composer/pane-share.test.ts +71 -0
- package/src/plugins/builtin/chart-composer/pane.tsx +103 -15
- package/src/plugins/builtin/chat/content/index.tsx +4 -1
- package/src/plugins/builtin/chat/controller/channels.ts +7 -1
- package/src/plugins/builtin/chat/controller/index.ts +14 -9
- package/src/plugins/builtin/chat/controller/notifications.ts +13 -3
- package/src/plugins/builtin/chat/controller/persistence.ts +0 -3
- package/src/plugins/builtin/chat/controller/realtime.ts +3 -3
- package/src/plugins/builtin/chat/controller/send.ts +1 -3
- package/src/plugins/builtin/chat/controller/session-runtime.ts +18 -11
- package/src/plugins/builtin/chat/controller/state.ts +1 -3
- package/src/plugins/builtin/chat/controller/storage.ts +0 -2
- package/src/plugins/builtin/chat/controller/utils.ts +4 -6
- package/src/plugins/builtin/chat/controller/view.ts +2 -2
- package/src/plugins/builtin/chat/controller.test.ts +142 -14
- package/src/plugins/builtin/chat/message/desktop.test.tsx +88 -0
- package/src/plugins/builtin/chat/message/desktop.tsx +3 -1
- package/src/plugins/builtin/chat/message/profile-popover.test.tsx +1 -29
- package/src/plugins/builtin/chat/profile-popover.ts +53 -22
- package/src/plugins/builtin/chat/sidebar.test.tsx +81 -0
- package/src/plugins/builtin/chat/sidebar.tsx +63 -0
- package/src/plugins/builtin/chat/test-harness.tsx +29 -1
- package/src/plugins/builtin/cloud/auth-actions.tsx +14 -7
- package/src/plugins/builtin/cloud/auth-commands.ts +21 -51
- package/src/plugins/builtin/cloud/auth-dialog.tsx +296 -0
- package/src/{components/onboarding/account-step/model.test.ts → plugins/builtin/cloud/auth-model.test.ts} +1 -1
- package/src/{components/onboarding/account-step/model.ts → plugins/builtin/cloud/auth-model.ts} +37 -3
- package/src/plugins/builtin/cloud/browser.tsx +9 -0
- package/src/plugins/builtin/cloud/buildout-module.tsx +23 -0
- package/src/plugins/builtin/cloud/device-signin.ts +2 -8
- package/src/plugins/builtin/cloud/index.tsx +2 -0
- package/src/plugins/builtin/cloud/plugin.tsx +14 -24
- package/src/plugins/builtin/cloud/upgrade-command.ts +13 -6
- package/src/plugins/builtin/cloud-tweets/pane-share.test.ts +56 -0
- package/src/plugins/builtin/cloud-tweets/pane.tsx +20 -5
- package/src/plugins/builtin/cloud-tweets/registration.ts +50 -6
- package/src/plugins/builtin/composite-plugins.ts +3 -1
- package/src/plugins/builtin/congress-trades/detail.tsx +43 -1
- package/src/plugins/builtin/congress-trades/model.test.ts +85 -0
- package/src/plugins/builtin/congress-trades/model.ts +69 -1
- package/src/plugins/builtin/congress-trades/pane.tsx +51 -2
- package/src/plugins/builtin/connections/index.ts +3 -0
- package/src/plugins/builtin/dividend-yield/client.ts +18 -0
- package/src/plugins/builtin/dividend-yield/pane.tsx +7 -6
- package/src/plugins/builtin/earnings/index.tsx +5 -3
- package/src/plugins/builtin/earnings/model.test.ts +19 -1
- package/src/plugins/builtin/earnings/model.ts +17 -15
- package/src/plugins/builtin/econ/calendar-model.ts +0 -5
- package/src/plugins/builtin/econ/index.test.tsx +6 -1
- package/src/plugins/builtin/fear-greed/charts.tsx +12 -8
- package/src/plugins/builtin/help/index.tsx +2 -2
- package/src/plugins/builtin/holders/thirteenf-match.ts +1 -2
- package/src/plugins/builtin/insider/index.tsx +27 -11
- package/src/plugins/builtin/kelly-sizer/index.tsx +4 -1
- package/src/plugins/builtin/layout-manager/index.tsx +17 -4
- package/src/plugins/builtin/news/index.tsx +11 -6
- package/src/plugins/builtin/news/wire/breaking/notifications.test.ts +2 -0
- package/src/plugins/builtin/news/wire/breaking/pane.test.tsx +2 -0
- package/src/plugins/builtin/news/wire/breaking/pane.tsx +4 -1
- package/src/plugins/builtin/news/wire/feed-config.test.ts +15 -1
- package/src/plugins/builtin/news/wire/feed-config.ts +25 -5
- package/src/plugins/builtin/news/wire/index.tsx +3 -3
- package/src/plugins/builtin/news/wire/industry-pane.tsx +7 -2
- package/src/plugins/builtin/news/wire/news/footer.ts +34 -1
- package/src/plugins/builtin/news/wire/news/preset-pane.tsx +4 -1
- package/src/plugins/builtin/news/wire/news/table.tsx +8 -2
- package/src/plugins/builtin/news/wire/rss/source.test.ts +12 -0
- package/src/plugins/builtin/news/wire/rss/source.ts +1 -1
- package/src/plugins/builtin/notes/files.ts +80 -0
- package/src/plugins/builtin/notes/index.tsx +3 -0
- package/src/plugins/builtin/notes/sync.test.ts +49 -0
- package/src/plugins/builtin/notes/sync.ts +98 -0
- package/src/plugins/builtin/options/index.tsx +1 -0
- package/src/plugins/builtin/options/view.test.tsx +25 -3
- package/src/plugins/builtin/options/view.tsx +1 -0
- package/src/plugins/builtin/portfolio-list/account-metrics.test.ts +22 -0
- package/src/plugins/builtin/portfolio-list/account-metrics.ts +12 -7
- package/src/plugins/builtin/portfolio-list/cli/render.ts +5 -3
- package/src/plugins/builtin/portfolio-list/column-values.ts +15 -4
- package/src/plugins/builtin/portfolio-list/header.tsx +13 -3
- package/src/plugins/builtin/portfolio-list/index.tsx +8 -0
- package/src/plugins/builtin/portfolio-list/metrics.test.ts +31 -1
- package/src/plugins/builtin/portfolio-list/pane/index.test.tsx +1 -0
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +10 -7
- package/src/plugins/builtin/portfolio-list/pane/streaming.ts +6 -1
- package/src/plugins/builtin/portfolio-list/position-metrics.ts +25 -6
- package/src/plugins/builtin/portfolio-list/summary/index.tsx +35 -21
- package/src/plugins/builtin/portfolio-list/summary/totals.ts +20 -6
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +5 -12
- package/src/plugins/builtin/research/equity-diagnostic-pane.test.tsx +329 -0
- package/src/plugins/builtin/research/equity-diagnostic-pane.tsx +582 -0
- package/src/plugins/builtin/research/index.test.ts +14 -0
- package/src/plugins/builtin/research/index.tsx +29 -0
- package/src/plugins/builtin/sec/index.tsx +24 -9
- package/src/plugins/builtin/sectors/index.tsx +14 -0
- package/src/plugins/builtin/shared/cloud-upgrade.ts +18 -11
- package/src/plugins/builtin/shared/public-pane.test.ts +12 -0
- package/src/plugins/builtin/shared/public-pane.ts +9 -0
- package/src/plugins/builtin/shared/public-share.ts +23 -0
- package/src/plugins/builtin/shared/ticker-source.ts +32 -0
- package/src/plugins/builtin/shared/ticker-surface.test.ts +27 -0
- package/src/plugins/builtin/shared/ticker-surface.ts +17 -0
- package/src/plugins/builtin/substack/api/cache.ts +7 -3
- package/src/plugins/builtin/substack/api/loaders.ts +36 -12
- package/src/plugins/builtin/substack/api/types.ts +2 -0
- package/src/plugins/builtin/substack/pane-state.ts +1 -1
- package/src/plugins/builtin/substack/pane.tsx +55 -12
- package/src/plugins/builtin/thirteenf/api.test.ts +1 -1
- package/src/plugins/builtin/thirteenf/api.ts +40 -18
- package/src/plugins/builtin/thirteenf/data.ts +15 -7
- package/src/plugins/builtin/thirteenf/pane.tsx +45 -10
- package/src/plugins/builtin/ticker-detail/index.tsx +10 -0
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +12 -4
- package/src/plugins/builtin/ticker-detail/quote-monitor/card.tsx +8 -2
- package/src/plugins/builtin/ticker-detail/settings.ts +12 -0
- package/src/plugins/builtin/treasury-auctions/index.tsx +2 -0
- package/src/plugins/builtin/world-indices/index.tsx +2 -0
- package/src/plugins/catalog-browser.test.ts +78 -0
- package/src/plugins/catalog-browser.ts +136 -0
- package/src/plugins/gridlock-notification.ts +2 -1
- package/src/plugins/ibkr/flex/index.test.ts +19 -0
- package/src/plugins/ibkr/flex/index.ts +1 -1
- package/src/plugins/pane-manager/gridlock.ts +87 -3
- package/src/plugins/pane-manager.test.ts +30 -0
- package/src/plugins/pane-manager.ts +6 -1
- package/src/plugins/prediction-markets/chart.tsx +2 -2
- package/src/plugins/prediction-markets/controller/catalog.ts +77 -2
- package/src/plugins/prediction-markets/controller/data.ts +7 -1
- package/src/plugins/prediction-markets/controller/index.ts +9 -2
- package/src/plugins/prediction-markets/controller/keyboard.ts +10 -14
- package/src/plugins/prediction-markets/detail/overview.tsx +21 -0
- package/src/plugins/prediction-markets/detail/pane.tsx +43 -34
- package/src/plugins/prediction-markets/detail/trades.tsx +34 -9
- package/src/plugins/prediction-markets/detail.test.tsx +29 -2
- package/src/plugins/prediction-markets/index.tsx +8 -4
- package/src/plugins/prediction-markets/navigation.ts +0 -1
- package/src/plugins/prediction-markets/pane.test.tsx +77 -0
- package/src/plugins/prediction-markets/pane.tsx +12 -0
- package/src/plugins/prediction-markets/plugin.test.tsx +36 -0
- package/src/plugins/prediction-markets/services/kalshi/adapter.ts +49 -9
- package/src/plugins/prediction-markets/services/polymarket/adapter.ts +31 -0
- package/src/plugins/prediction-markets/test-helpers.tsx +9 -0
- package/src/plugins/registry/index.ts +2 -0
- package/src/plugins/ticker-navigation.test.ts +24 -0
- package/src/plugins/ticker-navigation.ts +40 -0
- package/src/remote/schema.ts +1 -1
- package/src/renderers/browser/app-services.ts +61 -0
- package/src/renderers/browser/cloud-transport.test.ts +68 -0
- package/src/renderers/browser/cloud-transport.ts +48 -0
- package/src/renderers/browser/config-host.ts +58 -0
- package/src/renderers/browser/deeplink-bridge.test.ts +41 -0
- package/src/renderers/browser/deeplink-bridge.ts +22 -0
- package/src/renderers/browser/error-boundary.tsx +23 -0
- package/src/renderers/browser/main.tsx +64 -0
- package/src/renderers/browser/persistence.ts +74 -0
- package/src/renderers/browser/storage.test.ts +66 -0
- package/src/renderers/browser/storage.ts +50 -0
- package/src/renderers/browser/ticker-repository.ts +59 -0
- package/src/renderers/browser/ui-host.tsx +40 -0
- package/src/renderers/cloudflare/worker.test.ts +136 -0
- package/src/renderers/cloudflare/worker.ts +116 -0
- package/src/renderers/electrobun/bun/application-menu/index.ts +3 -2
- package/src/renderers/electrobun/bun/desktop/initialization.ts +1 -0
- package/src/renderers/electrobun/bun/desktop/plugin-state.ts +7 -1
- package/src/renderers/electrobun/view/app-services.ts +14 -3
- package/src/renderers/electrobun/view/build-assets.ts +12 -10
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -1
- package/src/renderers/electrobun/view/data-table/index.tsx +10 -1
- package/src/renderers/electrobun/view/desktop/controls.tsx +2 -0
- package/src/renderers/electrobun/view/dom-ui-host.tsx +143 -0
- package/src/renderers/electrobun/view/host/box.test.tsx +33 -0
- package/src/renderers/electrobun/view/host/box.tsx +11 -6
- package/src/renderers/electrobun/view/host/chart-surface.tsx +7 -1
- package/src/renderers/electrobun/view/host/input.tsx +11 -7
- package/src/renderers/electrobun/view/host/native.ts +0 -5
- package/src/renderers/electrobun/view/main.tsx +2 -0
- package/src/renderers/electrobun/view/remote/persistence.ts +5 -0
- package/src/renderers/electrobun/view/styles.css +107 -7
- package/src/renderers/electrobun/view/toast-host.test.tsx +78 -0
- package/src/renderers/electrobun/view/toast-host.tsx +69 -43
- package/src/renderers/electrobun/view/ui-host.tsx +6 -137
- package/src/renderers/opentui/start.tsx +2 -0
- package/src/renderers/share/layout-view.test.tsx +58 -0
- package/src/renderers/share/layout-view.tsx +133 -0
- package/src/renderers/share/main.tsx +102 -0
- package/src/renderers/share/styles.css +54 -0
- package/src/renderers/share/view.test.tsx +100 -0
- package/src/renderers/share/view.tsx +150 -0
- package/src/shares/api.test.ts +105 -0
- package/src/shares/api.ts +127 -0
- package/src/shares/chart-snapshot.test.ts +34 -0
- package/src/shares/chart-snapshot.ts +28 -0
- package/src/shares/location.test.ts +19 -0
- package/src/shares/location.ts +11 -0
- package/src/shares/pane.test.ts +110 -0
- package/src/shares/pane.ts +54 -0
- package/src/shares/payload.ts +177 -0
- package/src/sources/gloomberb-cloud/index.test.ts +61 -1
- package/src/sources/gloomberb-cloud/index.ts +86 -14
- package/src/sources/gloomberb-cloud/normalizers.test.ts +34 -0
- package/src/sources/gloomberb-cloud/normalizers.ts +5 -5
- package/src/sources/provider-router/history.test.ts +2 -2
- package/src/sources/provider-router/news.test.ts +34 -0
- package/src/sources/provider-router/news.ts +15 -1
- package/src/sources/sec-edgar.test.ts +59 -0
- package/src/sources/sec-edgar.ts +63 -23
- package/src/sources/yahoo-finance/mappers.ts +3 -0
- package/src/sources/yahoo-finance/snapshots.ts +10 -2
- package/src/sources/yahoo-finance/symbols.test.ts +10 -0
- package/src/sources/yahoo-finance/symbols.ts +13 -8
- package/src/sources/yahoo-finance.test.ts +1 -1
- package/src/sources/yahoo-finance.ts +6 -2
- package/src/state/app/bootstrap.ts +6 -7
- package/src/state/app/context/index.test.ts +41 -1
- package/src/state/app/context/index.test.tsx +34 -16
- package/src/state/selectors-ui.ts +0 -8
- package/src/sync/baseline.ts +32 -0
- package/src/sync/controller.test.ts +124 -1
- package/src/sync/controller.ts +54 -12
- package/src/sync/core-contributors.test.ts +44 -0
- package/src/sync/core-contributors.ts +59 -10
- package/src/sync/react.ts +22 -2
- package/src/sync/types.ts +12 -0
- package/src/theme/font-scale.ts +0 -11
- package/src/tickers/search/index.test.ts +27 -0
- package/src/tickers/search/upsert.ts +10 -0
- package/src/types/capability-route-source.ts +2 -1
- package/src/types/config.ts +35 -5
- package/src/types/desktop-menu.ts +1 -0
- package/src/types/plugin.ts +36 -0
- package/src/ui/context-menu.tsx +1 -1
- package/src/ui/host.tsx +4 -0
- package/src/ui/toast.tsx +2 -0
- package/src/utils/back-navigation.ts +0 -4
- package/src/utils/price-history.ts +11 -10
- package/src/utils/sec.test.ts +6 -0
- package/src/utils/sec.ts +1 -1
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { ImageSurface, Text, useUiCapabilities } from "../ui";
|
|
2
|
+
import { cloudLogoPath, type CloudLogoKind } from "../api-client/paths";
|
|
3
|
+
import { getCloudApiBaseUrl } from "../api-client/request";
|
|
4
|
+
import { resolveAssetDisplayKind } from "../market-data/market/format";
|
|
5
|
+
import { colors } from "../theme/colors";
|
|
6
|
+
|
|
7
|
+
export function resolveCompanyLogoSrc(input: {
|
|
8
|
+
symbol: string;
|
|
9
|
+
assetCategory?: string;
|
|
10
|
+
}): string | null {
|
|
11
|
+
const kind = logoKindForAsset(input.assetCategory);
|
|
12
|
+
if (!kind) return null;
|
|
13
|
+
const path = cloudLogoPath(kind, input.symbol);
|
|
14
|
+
return path ? `${getCloudApiBaseUrl()}${path}` : null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function CompanyLogo({
|
|
18
|
+
symbol,
|
|
19
|
+
assetCategory,
|
|
20
|
+
name,
|
|
21
|
+
width = 5,
|
|
22
|
+
height = 2,
|
|
23
|
+
}: {
|
|
24
|
+
symbol: string;
|
|
25
|
+
assetCategory?: string;
|
|
26
|
+
name?: string;
|
|
27
|
+
width?: number;
|
|
28
|
+
height?: number;
|
|
29
|
+
}) {
|
|
30
|
+
const { nativePaneChrome, cellWidthPx = 8, cellHeightPx = 18 } = useUiCapabilities();
|
|
31
|
+
const src = nativePaneChrome === true ? resolveCompanyLogoSrc({ symbol, assetCategory }) : null;
|
|
32
|
+
if (!src) return null;
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<ImageSurface
|
|
36
|
+
src={src}
|
|
37
|
+
alt={name || symbol}
|
|
38
|
+
width={width}
|
|
39
|
+
height={height}
|
|
40
|
+
marginRight={1}
|
|
41
|
+
flexShrink={0}
|
|
42
|
+
alignItems="center"
|
|
43
|
+
justifyContent="center"
|
|
44
|
+
objectFit="contain"
|
|
45
|
+
style={{
|
|
46
|
+
width: cellWidthPx * width,
|
|
47
|
+
height: cellHeightPx * height,
|
|
48
|
+
flexShrink: 0,
|
|
49
|
+
}}
|
|
50
|
+
>
|
|
51
|
+
<Text fg={colors.textDim}>{symbol.trim().charAt(0).toUpperCase() || "?"}</Text>
|
|
52
|
+
</ImageSurface>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function logoKindForAsset(assetCategory?: string): CloudLogoKind | null {
|
|
57
|
+
const kind = resolveAssetDisplayKind({ assetCategory });
|
|
58
|
+
if (kind === "cash" || kind === "contract") return null;
|
|
59
|
+
return kind === "crypto" ? "crypto" : "ticker";
|
|
60
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Box, ScrollBox, Text } from "../../ui";
|
|
2
2
|
import { TextAttributes, type ScrollBoxRenderable } from "../../ui";
|
|
3
|
-
import { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from "react";
|
|
3
|
+
import { useCallback, useEffect, useMemo, useRef, useState, type ReactNode, type RefObject } from "react";
|
|
4
4
|
import { t } from "../../i18n";
|
|
5
5
|
import { useAppLanguage } from "../../i18n/react";
|
|
6
6
|
import { displayWidth, formatTimeAgo } from "../../utils/format";
|
|
@@ -64,6 +64,8 @@ interface FeedDataTableStackViewProps {
|
|
|
64
64
|
isItemRead?: (item: FeedDataTableItem) => boolean;
|
|
65
65
|
onOpenItem?: (item: FeedDataTableItem, index: number) => void;
|
|
66
66
|
onOpenItemIdChange?: (itemId: string | null) => void;
|
|
67
|
+
scrollRef?: RefObject<ScrollBoxRenderable | null>;
|
|
68
|
+
onBodyScrollActivity?: () => void;
|
|
67
69
|
}
|
|
68
70
|
|
|
69
71
|
function timestampValue(item: FeedDataTableItem): number {
|
|
@@ -148,6 +150,8 @@ export function FeedDataTableStackView({
|
|
|
148
150
|
isItemRead,
|
|
149
151
|
onOpenItem,
|
|
150
152
|
onOpenItemIdChange,
|
|
153
|
+
scrollRef,
|
|
154
|
+
onBodyScrollActivity,
|
|
151
155
|
}: FeedDataTableStackViewProps) {
|
|
152
156
|
const language = useAppLanguage();
|
|
153
157
|
const [sortPreference, setSortPreference] = useState<SortPreference>({
|
|
@@ -362,6 +366,8 @@ export function FeedDataTableStackView({
|
|
|
362
366
|
emptyStateTitle={t(emptyStateTitle)}
|
|
363
367
|
emptyStateHint={emptyStateHint}
|
|
364
368
|
showHorizontalScrollbar={false}
|
|
369
|
+
scrollRef={scrollRef}
|
|
370
|
+
onBodyScrollActivity={onBodyScrollActivity}
|
|
365
371
|
/>
|
|
366
372
|
);
|
|
367
373
|
}
|
package/src/components/index.ts
CHANGED
|
@@ -14,6 +14,7 @@ export { TickerListTableView } from "./ticker/list-table-view";
|
|
|
14
14
|
export type { TickerListVisibleRange } from "./ticker/list-table-view";
|
|
15
15
|
export { TickerBadgeList } from "./ticker/badge/list";
|
|
16
16
|
export { InputSearchBar } from "./input-search-bar";
|
|
17
|
+
export { isTableScrollNearEnd, useTableLoadMore } from "./table-view-shared";
|
|
17
18
|
export { DataTableView } from "./data-table/view";
|
|
18
19
|
export type { DataTableKeyEvent, DataTableRootKeyContext } from "./data-table/view";
|
|
19
20
|
export { DataTableStackView } from "./data-table/stack-view";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { Box, Span, Text, useRendererHost, useUiCapabilities } from "../../ui";
|
|
1
|
+
import { Box, Span, Text, useContextMenu, useRendererHost, useUiCapabilities } from "../../ui";
|
|
2
2
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
3
3
|
import { t } from "../../i18n";
|
|
4
4
|
import { useShortcut, useViewport } from "../../react/input";
|
|
5
|
-
import { useAppDispatch, useAppSelector } from "../../state/app/context";
|
|
5
|
+
import { resolveTickerForPane, useAppDispatch, useAppSelector } from "../../state/app/context";
|
|
6
6
|
import type { DesktopWindowBridge } from "../../types/desktop-window";
|
|
7
7
|
import { findPaneInstance } from "../../types/config";
|
|
8
8
|
import type { PluginRegistry } from "../../plugins/registry";
|
|
@@ -20,6 +20,13 @@ import {
|
|
|
20
20
|
recordDoubleEscapeClose,
|
|
21
21
|
resetDoubleEscapeClose,
|
|
22
22
|
} from "../../utils/double-escape-close";
|
|
23
|
+
import { createShare, openLiveShareUrl } from "../../shares/api";
|
|
24
|
+
import { buildPaneSharePayload } from "../../shares/pane";
|
|
25
|
+
import type { ContextMenuItem } from "../../types/context-menu";
|
|
26
|
+
import {
|
|
27
|
+
PANE_MANAGEMENT_ACCELERATORS,
|
|
28
|
+
resolvePaneManagementShortcut,
|
|
29
|
+
} from "./shell/shortcuts";
|
|
23
30
|
|
|
24
31
|
interface DetachedPaneShellProps {
|
|
25
32
|
pluginRegistry: PluginRegistry;
|
|
@@ -35,6 +42,7 @@ export function DetachedPaneShell({ pluginRegistry, desktopWindowBridge }: Detac
|
|
|
35
42
|
const colors = useThemeColors();
|
|
36
43
|
const dispatch = useAppDispatch();
|
|
37
44
|
const rendererHost = useRendererHost();
|
|
45
|
+
const { showContextMenu } = useContextMenu();
|
|
38
46
|
const config = useAppSelector((state) => state.config);
|
|
39
47
|
const paneState = useAppSelector((state) => state.paneState);
|
|
40
48
|
const inputCaptured = useAppSelector((state) => state.inputCaptured);
|
|
@@ -43,19 +51,34 @@ export function DetachedPaneShell({ pluginRegistry, desktopWindowBridge }: Detac
|
|
|
43
51
|
typeof document === "undefined" ? true : document.hasFocus()
|
|
44
52
|
));
|
|
45
53
|
const { width, height } = useViewport();
|
|
46
|
-
const {
|
|
47
|
-
|
|
48
|
-
|
|
54
|
+
const {
|
|
55
|
+
cellHeightPx = 18,
|
|
56
|
+
nativePaneChrome,
|
|
57
|
+
publicSharing,
|
|
58
|
+
titleBarOverlay,
|
|
59
|
+
nativeWindowChrome = titleBarOverlay,
|
|
60
|
+
windowControls,
|
|
61
|
+
} = useUiCapabilities();
|
|
62
|
+
const showWindowControls = nativeWindowChrome && windowControls === "windows";
|
|
63
|
+
const titlebarLeadingInset = titleBarOverlay && nativeWindowChrome ? getTitlebarLeadingInset() : 0;
|
|
49
64
|
const instance = useAppSelector((state) => findPaneInstance(state.config.layout, desktopWindowBridge.paneId) ?? null);
|
|
50
65
|
const paneDef = instance ? pluginRegistry.panes.get(instance.paneId) ?? null : null;
|
|
51
66
|
const hasPaneSettings = !!instance && pluginRegistry.hasPaneSettings(instance.instanceId);
|
|
52
|
-
const quickSettings = instance ? pluginRegistry.resolvePaneQuickSettings(instance.instanceId) : [];
|
|
53
67
|
const titleState = useMemo(
|
|
54
|
-
() => ({ config, paneState }) as Parameters<typeof
|
|
68
|
+
() => ({ config, paneState }) as Parameters<typeof resolveTickerForPane>[0],
|
|
55
69
|
[config, paneState],
|
|
56
70
|
);
|
|
71
|
+
const sharePayload = useMemo(() => instance && publicSharing
|
|
72
|
+
? buildPaneSharePayload(
|
|
73
|
+
pluginRegistry,
|
|
74
|
+
instance,
|
|
75
|
+
paneState[instance.instanceId] ?? {},
|
|
76
|
+
resolveTickerForPane(titleState, instance.instanceId),
|
|
77
|
+
)
|
|
78
|
+
: null, [instance, paneState, pluginRegistry, publicSharing, titleState]);
|
|
79
|
+
const quickSettings = instance ? pluginRegistry.resolvePaneQuickSettings(instance.instanceId) : [];
|
|
57
80
|
const title = instance && paneDef
|
|
58
|
-
? getPaneDisplayTitle(titleState, instance, paneDef)
|
|
81
|
+
? getPaneDisplayTitle(titleState, instance, paneDef, pluginRegistry.panes)
|
|
59
82
|
: "Detached Pane";
|
|
60
83
|
const focused = windowFocused;
|
|
61
84
|
|
|
@@ -112,13 +135,59 @@ export function DetachedPaneShell({ pluginRegistry, desktopWindowBridge }: Detac
|
|
|
112
135
|
|
|
113
136
|
const startWindowDrag = useCallback(() => {
|
|
114
137
|
focusPane();
|
|
115
|
-
void rendererHost.startWindowDrag?.();
|
|
116
|
-
}, [focusPane, rendererHost]);
|
|
138
|
+
if (nativeWindowChrome) void rendererHost.startWindowDrag?.();
|
|
139
|
+
}, [focusPane, nativeWindowChrome, rendererHost]);
|
|
140
|
+
|
|
141
|
+
const sharePane = useCallback(async () => {
|
|
142
|
+
if (!sharePayload) return;
|
|
143
|
+
try {
|
|
144
|
+
const { id } = await createShare(sharePayload);
|
|
145
|
+
await rendererHost.copyText(openLiveShareUrl(id));
|
|
146
|
+
pluginRegistry.notify({ body: "Share link copied to clipboard", type: "success" });
|
|
147
|
+
} catch (error) {
|
|
148
|
+
pluginRegistry.notify({
|
|
149
|
+
body: error instanceof Error ? error.message : "Could not share this pane.",
|
|
150
|
+
type: "error",
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}, [pluginRegistry, rendererHost, sharePayload]);
|
|
117
154
|
|
|
118
|
-
|
|
155
|
+
useShortcut((event) => {
|
|
156
|
+
if (resolvePaneManagementShortcut(event) !== "share" || !sharePayload) return;
|
|
157
|
+
if (inputCaptured && event.ctrl && !event.meta && !event.super) return;
|
|
158
|
+
event.preventDefault();
|
|
159
|
+
event.stopPropagation();
|
|
160
|
+
void sharePane();
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
const openActions = useCallback((event?: { stopPropagation?: () => void; preventDefault?: () => void }) => {
|
|
119
164
|
stopMouse(event);
|
|
120
|
-
|
|
121
|
-
|
|
165
|
+
focusPane();
|
|
166
|
+
const items: ContextMenuItem[] = [];
|
|
167
|
+
if (hasPaneSettings) {
|
|
168
|
+
items.push({
|
|
169
|
+
id: "settings",
|
|
170
|
+
label: "Settings",
|
|
171
|
+
onSelect: () => pluginRegistry.openPaneSettingsFn(desktopWindowBridge.paneId),
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
if (sharePayload) items.push({
|
|
175
|
+
id: "share-pane",
|
|
176
|
+
label: "Share Pane",
|
|
177
|
+
accelerator: PANE_MANAGEMENT_ACCELERATORS.share,
|
|
178
|
+
onSelect: sharePane,
|
|
179
|
+
});
|
|
180
|
+
void showContextMenu({
|
|
181
|
+
kind: "pane",
|
|
182
|
+
paneId: desktopWindowBridge.paneId,
|
|
183
|
+
paneType: instance?.paneId ?? "",
|
|
184
|
+
title,
|
|
185
|
+
floating: true,
|
|
186
|
+
}, items, event).then((shown) => {
|
|
187
|
+
if (!shown && hasPaneSettings) pluginRegistry.openPaneSettingsFn(desktopWindowBridge.paneId);
|
|
188
|
+
else if (!shown && sharePayload) void sharePane();
|
|
189
|
+
});
|
|
190
|
+
}, [desktopWindowBridge.paneId, focusPane, hasPaneSettings, instance?.paneId, pluginRegistry, sharePane, sharePayload, showContextMenu, title]);
|
|
122
191
|
const toggleQuickSetting = useCallback((key: string, event?: { stopPropagation?: () => void; preventDefault?: () => void }) => {
|
|
123
192
|
stopMouse(event);
|
|
124
193
|
focusPane();
|
|
@@ -224,14 +293,15 @@ export function DetachedPaneShell({ pluginRegistry, desktopWindowBridge }: Detac
|
|
|
224
293
|
</Box>
|
|
225
294
|
))}
|
|
226
295
|
<Box flexGrow={1} minWidth={0} />
|
|
227
|
-
{hasPaneSettings && (
|
|
296
|
+
{(hasPaneSettings || sharePayload) && (
|
|
228
297
|
<Text
|
|
229
298
|
fg={paneTitleText(focused, true, colors)}
|
|
230
299
|
selectable={false}
|
|
231
300
|
className="electrobun-webkit-app-region-no-drag"
|
|
232
301
|
data-gloom-role="pane-action"
|
|
233
302
|
data-gloom-interactive="true"
|
|
234
|
-
|
|
303
|
+
aria-label="Pane actions"
|
|
304
|
+
onMouseDown={openActions}
|
|
235
305
|
>
|
|
236
306
|
{" ... "}
|
|
237
307
|
</Text>
|
|
@@ -164,9 +164,9 @@ export function Header({
|
|
|
164
164
|
const rendererHost = useRendererHost();
|
|
165
165
|
const baseCurrency = useAppSelector(selectBaseCurrency);
|
|
166
166
|
const appActive = useAppActive();
|
|
167
|
-
const { titleBarOverlay, windowControls } = useUiCapabilities();
|
|
168
|
-
const showWindowControls = windowControls === "windows";
|
|
169
|
-
const titlebarLeadingInset = titleBarOverlay ? getTitlebarLeadingInset() : 0;
|
|
167
|
+
const { titleBarOverlay, nativeWindowChrome = titleBarOverlay, windowControls } = useUiCapabilities();
|
|
168
|
+
const showWindowControls = nativeWindowChrome && windowControls === "windows";
|
|
169
|
+
const titlebarLeadingInset = titleBarOverlay && nativeWindowChrome ? getTitlebarLeadingInset() : 0;
|
|
170
170
|
const spyQuoteEntry = useQuoteEntry("SPY", null);
|
|
171
171
|
const spyQuote = useResolvedEntryValue(spyQuoteEntry);
|
|
172
172
|
const mktState = spyQuote?.marketState;
|
|
@@ -198,9 +198,9 @@ export function Header({
|
|
|
198
198
|
: "SPY —";
|
|
199
199
|
|
|
200
200
|
const startWindowDrag = useCallback(() => {
|
|
201
|
-
if (!titleBarOverlay) return;
|
|
201
|
+
if (!titleBarOverlay || !nativeWindowChrome) return;
|
|
202
202
|
void rendererHost.startWindowDrag?.();
|
|
203
|
-
}, [rendererHost, titleBarOverlay]);
|
|
203
|
+
}, [nativeWindowChrome, rendererHost, titleBarOverlay]);
|
|
204
204
|
|
|
205
205
|
// Market status
|
|
206
206
|
const mktCountdown = mktState ? marketStateCountdown(mktState, now) : null;
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import { resolveCollectionForPane, resolveTickerForPane, type AppState } from "../../../state/app/context";
|
|
2
|
-
import { t } from "../../../i18n";
|
|
3
|
-
import {
|
|
2
|
+
import { t, tf } from "../../../i18n";
|
|
3
|
+
import {
|
|
4
|
+
findPaneInstance,
|
|
5
|
+
TICKER_RESEARCH_PANE_ID,
|
|
6
|
+
type PaneInstanceConfig,
|
|
7
|
+
} from "../../../types/config";
|
|
4
8
|
import type { PaneDef } from "../../../types/plugin";
|
|
5
9
|
|
|
6
|
-
|
|
10
|
+
/** Single-cell link glyph: emoji link icons render double-width in terminals. */
|
|
11
|
+
const LINK_GLYPH = "\u29c9";
|
|
12
|
+
|
|
13
|
+
function getBasePaneDisplayTitle(
|
|
7
14
|
state: Pick<AppState, "config" | "paneState">,
|
|
8
15
|
instance: PaneInstanceConfig,
|
|
9
16
|
paneDef: PaneDef,
|
|
@@ -38,6 +45,27 @@ export function getPaneDisplayTitle(
|
|
|
38
45
|
?? t(paneDef.name);
|
|
39
46
|
}
|
|
40
47
|
|
|
48
|
+
// A source pane owns the cursor symbol; echoing it in its own title would just repeat the row.
|
|
49
|
+
if (paneDef.tickerSource) return t(paneDef.name);
|
|
50
|
+
|
|
41
51
|
const ticker = resolveTickerForPane(state as AppState, instance.instanceId);
|
|
42
52
|
return ticker ? `${t(paneDef.name)}: ${ticker}` : t(paneDef.name);
|
|
43
53
|
}
|
|
54
|
+
|
|
55
|
+
export function getPaneDisplayTitle(
|
|
56
|
+
state: Pick<AppState, "config" | "paneState">,
|
|
57
|
+
instance: PaneInstanceConfig,
|
|
58
|
+
paneDef: PaneDef,
|
|
59
|
+
panes?: ReadonlyMap<string, PaneDef>,
|
|
60
|
+
): string {
|
|
61
|
+
const title = getBasePaneDisplayTitle(state, instance, paneDef);
|
|
62
|
+
if (instance.paneId !== TICKER_RESEARCH_PANE_ID || instance.binding?.kind !== "follow" || !panes) {
|
|
63
|
+
return title;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const source = findPaneInstance(state.config.layout, instance.binding.sourceInstanceId);
|
|
67
|
+
const sourceDef = source ? panes.get(source.paneId) : null;
|
|
68
|
+
if (!source || !sourceDef) return title;
|
|
69
|
+
const sourceTitle = getBasePaneDisplayTitle(state, source, sourceDef);
|
|
70
|
+
return `${title} ${LINK_GLYPH} ${tf("Linked to {source}", { source: sourceTitle })}`;
|
|
71
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useCallback
|
|
1
|
+
import { useCallback } from "react";
|
|
2
2
|
import {
|
|
3
3
|
floatAtRect,
|
|
4
4
|
getRememberedFloatingRect,
|
|
@@ -10,7 +10,6 @@ import {
|
|
|
10
10
|
type LayoutBounds,
|
|
11
11
|
type ResolvedPane,
|
|
12
12
|
} from "../../../plugins/pane-manager";
|
|
13
|
-
import type { AppAction } from "../../../state/app/context";
|
|
14
13
|
import type { LayoutConfig } from "../../../types/config";
|
|
15
14
|
import {
|
|
16
15
|
finalizePaneDragRelease,
|
|
@@ -32,7 +31,6 @@ interface UseShellActiveDragOptions {
|
|
|
32
31
|
appHeaderHeight: number;
|
|
33
32
|
bounds: LayoutBounds;
|
|
34
33
|
contentHeight: number;
|
|
35
|
-
dispatch: Dispatch<AppAction>;
|
|
36
34
|
dockGeometryOptions: DockGeometryOptions;
|
|
37
35
|
dockLeafLayouts: DockLeafLayout[];
|
|
38
36
|
dragRuntime: ShellDragRuntimeState;
|
|
@@ -52,7 +50,6 @@ export function useShellActiveDrag({
|
|
|
52
50
|
appHeaderHeight,
|
|
53
51
|
bounds,
|
|
54
52
|
contentHeight,
|
|
55
|
-
dispatch,
|
|
56
53
|
dockGeometryOptions,
|
|
57
54
|
dockLeafLayouts,
|
|
58
55
|
dragRuntime,
|
|
@@ -168,16 +165,13 @@ export function useShellActiveDrag({
|
|
|
168
165
|
? getRememberedFloatingRect(baseLayout, drag.paneId, width, contentHeight, pane?.def)
|
|
169
166
|
: drag.origRect;
|
|
170
167
|
const releaseRect = resolvePaneDragFloatingRect(drag, baseRect, preciseX, preciseShellY, width, contentHeight);
|
|
171
|
-
const
|
|
168
|
+
const nextLayout = finalizePaneDragRelease(baseLayout, drag.paneId, releaseRect, dockPreviewRef.current);
|
|
172
169
|
if (windowMode) {
|
|
173
|
-
updateWindowModePreviewLayout(
|
|
170
|
+
updateWindowModePreviewLayout(nextLayout, drag.paneId);
|
|
174
171
|
} else {
|
|
175
|
-
persistLayout(
|
|
172
|
+
persistLayout(nextLayout);
|
|
176
173
|
}
|
|
177
174
|
focusPane(drag.paneId);
|
|
178
|
-
if (!windowMode && releaseResult.shouldShowGridlockTip) {
|
|
179
|
-
dispatch({ type: "SHOW_GRIDLOCK_TIP" });
|
|
180
|
-
}
|
|
181
175
|
updateDockPreview(null);
|
|
182
176
|
setDragCursor(null);
|
|
183
177
|
updateDragFloatingRect(null);
|
|
@@ -201,7 +195,6 @@ export function useShellActiveDrag({
|
|
|
201
195
|
appHeaderHeight,
|
|
202
196
|
bounds,
|
|
203
197
|
contentHeight,
|
|
204
|
-
dispatch,
|
|
205
198
|
dockGeometryOptions,
|
|
206
199
|
dividerPreviewRef,
|
|
207
200
|
dockLeafLayouts,
|
|
@@ -46,11 +46,6 @@ export type DragPreview =
|
|
|
46
46
|
rect: FloatingRect;
|
|
47
47
|
};
|
|
48
48
|
|
|
49
|
-
export interface PaneDragReleaseResult {
|
|
50
|
-
nextLayout: LayoutConfig;
|
|
51
|
-
shouldShowGridlockTip: boolean;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
49
|
export interface PaneDragRectState {
|
|
55
50
|
mode: "docked" | "floating";
|
|
56
51
|
startX: number;
|
|
@@ -272,25 +267,14 @@ export function finalizePaneDragRelease(
|
|
|
272
267
|
paneId: string,
|
|
273
268
|
previewRect: FloatingRect,
|
|
274
269
|
dockPreview: DragPreview | null,
|
|
275
|
-
):
|
|
270
|
+
): LayoutConfig {
|
|
276
271
|
if (dockPreview?.kind === "dock") {
|
|
277
|
-
return
|
|
278
|
-
nextLayout: applyDrop(layout, paneId, dockPreview.target),
|
|
279
|
-
shouldShowGridlockTip: false,
|
|
280
|
-
};
|
|
272
|
+
return applyDrop(layout, paneId, dockPreview.target);
|
|
281
273
|
}
|
|
282
|
-
|
|
283
274
|
if (dockPreview?.kind === "snap") {
|
|
284
|
-
return
|
|
285
|
-
nextLayout: floatAtRect(layout, paneId, dockPreview.rect),
|
|
286
|
-
shouldShowGridlockTip: true,
|
|
287
|
-
};
|
|
275
|
+
return floatAtRect(layout, paneId, dockPreview.rect);
|
|
288
276
|
}
|
|
289
|
-
|
|
290
|
-
return {
|
|
291
|
-
nextLayout: floatAtRect(layout, paneId, previewRect),
|
|
292
|
-
shouldShowGridlockTip: false,
|
|
293
|
-
};
|
|
277
|
+
return floatAtRect(layout, paneId, previewRect);
|
|
294
278
|
}
|
|
295
279
|
|
|
296
280
|
export function makeSnapGuides(width: number, height: number): SnapGuide[] {
|
|
@@ -15,7 +15,6 @@ import {
|
|
|
15
15
|
type LayoutBounds,
|
|
16
16
|
type ResolvedPane,
|
|
17
17
|
} from "../../../../plugins/pane-manager";
|
|
18
|
-
import type { AppAction } from "../../../../state/app/context";
|
|
19
18
|
import type { LayoutConfig } from "../../../../types/config";
|
|
20
19
|
import {
|
|
21
20
|
constrainFloatingRectToBounds,
|
|
@@ -165,7 +164,6 @@ interface UseShellPointerRuntimeOptions {
|
|
|
165
164
|
bounds: LayoutBounds;
|
|
166
165
|
closePaneMenu: () => void;
|
|
167
166
|
contentHeight: number;
|
|
168
|
-
dispatch: Dispatch<AppAction>;
|
|
169
167
|
dockGeometryOptions: DockGeometryOptions;
|
|
170
168
|
dockDividerLayouts: DockDividerLayout[];
|
|
171
169
|
dockLeafLayouts: DockLeafLayout[];
|
|
@@ -193,6 +191,7 @@ interface UseShellPointerRuntimeOptions {
|
|
|
193
191
|
visibleLayout: LayoutConfig;
|
|
194
192
|
width: number;
|
|
195
193
|
windowMode: WindowEditState | null;
|
|
194
|
+
commandBarOpen: boolean;
|
|
196
195
|
}
|
|
197
196
|
|
|
198
197
|
export function useShellPointerRuntime({
|
|
@@ -200,7 +199,6 @@ export function useShellPointerRuntime({
|
|
|
200
199
|
bounds,
|
|
201
200
|
closePaneMenu,
|
|
202
201
|
contentHeight,
|
|
203
|
-
dispatch,
|
|
204
202
|
dockGeometryOptions,
|
|
205
203
|
dockDividerLayouts,
|
|
206
204
|
dockLeafLayouts,
|
|
@@ -224,12 +222,12 @@ export function useShellPointerRuntime({
|
|
|
224
222
|
visibleLayout,
|
|
225
223
|
width,
|
|
226
224
|
windowMode,
|
|
225
|
+
commandBarOpen,
|
|
227
226
|
}: UseShellPointerRuntimeOptions) {
|
|
228
227
|
const handleActiveDrag = useShellActiveDrag({
|
|
229
228
|
appHeaderHeight,
|
|
230
229
|
bounds,
|
|
231
230
|
contentHeight,
|
|
232
|
-
dispatch,
|
|
233
231
|
dockGeometryOptions,
|
|
234
232
|
dockLeafLayouts,
|
|
235
233
|
focusPane,
|
|
@@ -282,6 +280,7 @@ export function useShellPointerRuntime({
|
|
|
282
280
|
setMenuState,
|
|
283
281
|
transientFocusActive,
|
|
284
282
|
windowMode,
|
|
283
|
+
commandBarOpen,
|
|
285
284
|
});
|
|
286
285
|
|
|
287
286
|
return {
|
|
@@ -62,6 +62,7 @@ function createShellPluginRegistry(options?: {
|
|
|
62
62
|
hasPaneSettings: (paneId: string) => paneId === "portfolio-list:main",
|
|
63
63
|
openPaneSettingsFn: () => {},
|
|
64
64
|
openCommandBar: () => {},
|
|
65
|
+
showPane: () => {},
|
|
65
66
|
openWindowMode: () => {},
|
|
66
67
|
openWindowModeFn: () => {},
|
|
67
68
|
updateLayoutFn: () => {},
|
|
@@ -356,7 +357,8 @@ describe("Shell", () => {
|
|
|
356
357
|
expect(resolvePaneManagementShortcut({ ...base, name: "D", key: "D" })).toBe("toggle-floating");
|
|
357
358
|
expect(resolvePaneManagementShortcut({ ...base, name: "o", key: "o" })).toBe("pop-out");
|
|
358
359
|
expect(resolvePaneManagementShortcut({ ...base, name: "c", key: "c" })).toBe("copy-screenshot");
|
|
359
|
-
expect(resolvePaneManagementShortcut({ ...base, name: "
|
|
360
|
+
expect(resolvePaneManagementShortcut({ ...base, name: "s", key: "s" })).toBe("share");
|
|
361
|
+
expect(resolvePaneManagementShortcut({ ...base, name: "l", key: "l" })).toBe("layout-gallery");
|
|
360
362
|
expect(resolvePaneManagementShortcut({ ...base, name: "f", key: "f" })).toBe("toggle-fullscreen");
|
|
361
363
|
expect(resolvePaneManagementShortcut({ ...base, name: "g", key: "g" })).toBe("gridlock-all");
|
|
362
364
|
expect(resolvePaneManagementShortcut({ ...base, name: "m", key: "m" })).toBe("window-mode");
|
|
@@ -366,6 +368,18 @@ describe("Shell", () => {
|
|
|
366
368
|
expect(resolvePaneManagementShortcut({ ...base, name: "d", key: "d", meta: false, super: false })).toBeNull();
|
|
367
369
|
});
|
|
368
370
|
|
|
371
|
+
test("opens the layout browser from the primary Shift-L shortcut", async () => {
|
|
372
|
+
const config = createDefaultConfig("/tmp/gloomberb-shell-layout-browser-shortcut-test");
|
|
373
|
+
const opened: string[] = [];
|
|
374
|
+
const registry = createShellPluginRegistry();
|
|
375
|
+
registry.showPane = (paneId) => opened.push(paneId);
|
|
376
|
+
await renderShellForWindowModeTest(createInitialState(config), { registry });
|
|
377
|
+
|
|
378
|
+
await emitKeypress({ name: "l", ctrl: true, shift: true });
|
|
379
|
+
|
|
380
|
+
expect(opened).toEqual(["layout-marketplace"]);
|
|
381
|
+
});
|
|
382
|
+
|
|
369
383
|
test("toggles the focused pane fullscreen without persisting layout", async () => {
|
|
370
384
|
const config = createDefaultConfig("/tmp/gloomberb-shell-fullscreen-shortcut-test");
|
|
371
385
|
const mainPane = requireLayoutInstance(config, "portfolio-list:main");
|
|
@@ -478,8 +492,8 @@ describe("Shell", () => {
|
|
|
478
492
|
|
|
479
493
|
const frame = testSetup!.captureCharFrame();
|
|
480
494
|
const rows = frame.split("\n");
|
|
481
|
-
expect(rows[2]?.indexOf("
|
|
482
|
-
expect(rows[5]?.indexOf("
|
|
495
|
+
expect(rows[2]?.indexOf(":: Main Portfolio") ?? -1).toBeLessThan(0);
|
|
496
|
+
expect(rows[5]?.indexOf(":: Main Portfolio")).toBeGreaterThanOrEqual(14);
|
|
483
497
|
|
|
484
498
|
await act(async () => {
|
|
485
499
|
await testSetup!.mockMouse.release(16, 6);
|