gloomberb 0.15.6 → 0.15.7
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 +2 -2
- package/README.zh-CN.md +1 -1
- package/package.json +1 -1
- package/src/api-client/data.ts +37 -10
- package/src/api-client/estimate-revisions.ts +1 -1
- package/src/api-client/futures-curve.ts +1 -1
- package/src/api-client/index.ts +6 -0
- package/src/api-client/market-discovery.ts +84 -0
- package/src/api-client/paths.ts +14 -11
- package/src/api-client/request.ts +12 -2
- package/src/api-client/tape.ts +2 -2
- package/src/api-client/types.ts +2 -0
- package/src/app/dialog-bridge.tsx +33 -0
- package/src/app/pane-runtime/index.tsx +7 -2
- package/src/app/pane-runtime/pane-settings-runtime.tsx +2 -1
- package/src/app/pane-runtime/pane-template-runtime.ts +8 -28
- package/src/app/pane-runtime/plugin-bindings.ts +34 -12
- package/src/app/pane-runtime/ticker-open-runtime.ts +5 -3
- package/src/app/runtime/broker-import.ts +1 -1
- package/src/app/runtime/desktop-menu.ts +9 -6
- package/src/app/runtime/plugin-bindings.ts +7 -1
- package/src/app/runtime/ticker-refresh.ts +1 -1
- package/src/app.tsx +12 -0
- package/src/brokers/directory.ts +11 -2
- package/src/brokers/profile-form.ts +2 -1
- package/src/brokers/remove-profile.ts +61 -0
- package/src/brokers/signed-in/connect.ts +20 -7
- package/src/brokers/signed-in/sign-in-dialog.tsx +68 -30
- package/src/cli/desktop-pane-shot.ts +2 -2
- package/src/cli/history-rows.ts +1 -1
- package/src/cli/pane-functions/function-help.ts +3 -3
- package/src/cli/ticker-resolution.ts +2 -2
- package/src/components/command-bar/action-runtime.ts +7 -67
- package/src/components/command-bar/commands/direct/index.ts +9 -5
- package/src/components/command-bar/commands/direct/runtime.ts +12 -11
- package/src/components/command-bar/commands/plugin/actions.ts +6 -35
- package/src/components/command-bar/helpers.ts +3 -31
- package/src/components/command-bar/keyboard-handlers.ts +7 -219
- package/src/components/command-bar/keyboard-shortcuts.ts +25 -99
- package/src/components/command-bar/layout-items/current-layout.ts +2 -1
- package/src/components/command-bar/layout-items/focused-pane.ts +2 -1
- package/src/components/command-bar/layout-items/types.ts +2 -0
- package/src/components/command-bar/layout-items.ts +3 -0
- package/src/components/command-bar/list/model.ts +1 -1
- package/src/components/command-bar/list/navigation.ts +5 -12
- package/src/components/command-bar/pane-actions.ts +17 -14
- package/src/components/command-bar/pane-settings.ts +7 -250
- package/src/components/command-bar/pane-templates/workflow.ts +6 -13
- package/src/components/command-bar/panel/index.tsx +4 -110
- package/src/components/command-bar/panel/layout.ts +4 -16
- package/src/components/command-bar/panel/runtime.ts +1 -87
- package/src/components/command-bar/panel/state.ts +12 -29
- package/src/components/command-bar/panel/types.ts +2 -26
- package/src/components/command-bar/picker-activation.ts +7 -56
- package/src/components/command-bar/routes/root/plugin-install.ts +3 -3
- package/src/components/command-bar/routes/root/search-report.ts +2 -1
- package/src/components/command-bar/routing/actions.ts +21 -59
- package/src/components/command-bar/routing/confirm.ts +15 -88
- package/src/components/command-bar/routing/effects.ts +1 -20
- package/src/components/command-bar/routing/launch-request.ts +1 -36
- package/src/components/command-bar/routing/list-state.ts +5 -36
- package/src/components/command-bar/selection-runtime.ts +6 -35
- package/src/components/command-bar/surface/environment.ts +10 -6
- package/src/components/command-bar/surface/index.tsx +4 -37
- package/src/components/command-bar/workflow/alert.ts +23 -17
- package/src/components/command-bar/workflow/broker.ts +30 -40
- package/src/components/command-bar/workflow/builtin.ts +33 -38
- package/src/components/command-bar/workflow/collection-actions.ts +18 -21
- package/src/components/command-bar/workflow/collection-ticker.ts +4 -4
- package/src/components/command-bar/workflow/coordinator.ts +27 -156
- package/src/components/command-bar/workflow/fields.ts +6 -22
- package/src/components/command-bar/workflow/submit.ts +28 -43
- package/src/components/command-bar/workflow/ticker-listing-picker.ts +12 -9
- package/src/components/command-bar/workflow/tickers.ts +2 -2
- package/src/components/command-bar/workflow/types.ts +10 -35
- package/src/components/feedback-dialog.tsx +1 -13
- package/src/components/form-modal/broker-step.tsx +119 -0
- package/src/components/form-modal/confirm.tsx +145 -0
- package/src/components/form-modal/content.tsx +698 -0
- package/src/components/form-modal/deps.ts +77 -0
- package/src/components/form-modal/field-row.tsx +318 -0
- package/src/components/form-modal/host.tsx +169 -0
- package/src/components/form-modal/index.ts +2 -0
- package/src/components/form-modal/model.ts +131 -0
- package/src/components/form-modal/request.ts +67 -0
- package/src/components/form-modal/routes.ts +139 -0
- package/src/components/layout/shell/index.tsx +11 -0
- package/src/components/layout/status-bar.tsx +2 -1
- package/src/components/onboarding/first-run-workspace.ts +1 -1
- package/src/components/onboarding/onboarding-frame.tsx +4 -1
- package/src/components/onboarding/onboarding-wizard.tsx +1 -1
- package/src/components/pane-settings-dialog.tsx +7 -1
- package/src/components/pane-template-wizard.tsx +4 -149
- package/src/components/sign-in-code-panel.tsx +22 -9
- package/src/components/textarea-keys.ts +13 -0
- package/src/components/ui/button.tsx +3 -2
- package/src/components/ui/confirm-dialog.tsx +62 -10
- package/src/components/ui/frame.tsx +7 -2
- package/src/components/ui/list-view.tsx +16 -9
- package/src/core/app-runtime.ts +1 -1
- package/src/core/state/app/types.ts +1 -15
- package/src/data/config/home.ts +82 -11
- package/src/data/config/store/node.ts +29 -16
- package/src/i18n/es.ts +53 -7
- package/src/i18n/ja.ts +53 -7
- package/src/i18n/ko.ts +53 -7
- package/src/i18n/zh-cn.ts +53 -7
- package/src/i18n/zh-tw.ts +53 -7
- package/src/layout-marketplace/gallery.tsx +11 -3
- package/src/market-data/coordinator/fx-legs.ts +1 -1
- package/src/market-data/history-session.ts +3 -5
- package/src/market-data/market/freshness.ts +1 -1
- package/src/market-data/market/status.ts +1 -1
- package/src/market-data/quotes/metadata.ts +3 -3
- package/src/market-data/quotes/resolution.ts +3 -3
- package/src/news/types.ts +1 -1
- package/src/plugins/builtin/alerts/alert-engine.ts +2 -0
- package/src/plugins/builtin/alerts/cli.ts +2 -2
- package/src/plugins/builtin/alerts/types.ts +2 -0
- package/src/plugins/builtin/broker-manager/add-flow.tsx +625 -0
- package/src/plugins/builtin/broker-manager/add-request.ts +34 -0
- package/src/plugins/builtin/broker-manager/detail.tsx +128 -50
- package/src/plugins/builtin/broker-manager/footer.ts +6 -5
- package/src/plugins/builtin/broker-manager/index.tsx +62 -21
- package/src/plugins/builtin/broker-manager/model.ts +7 -0
- package/src/plugins/builtin/broker-manager/pane-actions.tsx +47 -44
- package/src/plugins/builtin/cloud/company-picker.tsx +658 -0
- package/src/plugins/builtin/credit-boards/model.ts +1 -1
- package/src/plugins/builtin/dividend-yield/browser.tsx +2 -25
- package/src/plugins/builtin/dividend-yield/client.ts +34 -122
- package/src/plugins/builtin/dividend-yield/index.tsx +9 -9
- package/src/plugins/builtin/dividend-yield/provider-client.ts +1 -1
- package/src/plugins/builtin/estimate-revisions/client.ts +3 -3
- package/src/plugins/builtin/estimate-revisions/pane.tsx +2 -2
- package/src/plugins/builtin/executives/pane.tsx +13 -4
- package/src/plugins/builtin/filing-events/pane.tsx +23 -6
- package/src/plugins/builtin/futures/contracts.ts +3 -3
- package/src/plugins/builtin/futures/returns.ts +1 -1
- package/src/plugins/builtin/futures-curve/client.ts +1 -1
- package/src/plugins/builtin/futures-curve/model.ts +1 -1
- package/src/plugins/builtin/help/index.tsx +8 -3
- package/src/plugins/builtin/market-heatmap/data.ts +13 -256
- package/src/plugins/builtin/market-heatmap/index.tsx +5 -15
- package/src/plugins/builtin/market-movers/client.ts +1 -1
- package/src/plugins/builtin/market-movers/screener.ts +60 -142
- package/src/plugins/builtin/market-valuation/defs.ts +1 -2
- package/src/plugins/builtin/market-valuation/sources.ts +1 -3
- package/src/plugins/builtin/news/wire/default-feeds.ts +2 -8
- package/src/plugins/builtin/news/wire/feed-config.ts +5 -1
- package/src/plugins/builtin/news/wire/persisted-articles.ts +9 -5
- package/src/plugins/builtin/news/wire/rss/cli.ts +1 -1
- package/src/plugins/builtin/news/wire/rss/managed-feed.ts +19 -0
- package/src/plugins/builtin/news/wire/rss/parser.ts +18 -9
- package/src/plugins/builtin/news/wire/rss/source.ts +1 -1
- package/src/plugins/builtin/plugin-marketplace/model.ts +5 -0
- package/src/plugins/builtin/plugin-marketplace/pane.tsx +4 -2
- package/src/plugins/builtin/relative-rotation/client.ts +1 -1
- package/src/plugins/builtin/research/analyst-model.ts +1 -1
- package/src/plugins/builtin/research/event-model.ts +1 -1
- package/src/plugins/builtin/risk-factors/pane.tsx +25 -10
- package/src/plugins/builtin/shared/pro-feature-wall.tsx +47 -0
- package/src/plugins/builtin/short-interest/client.ts +14 -106
- package/src/plugins/builtin/short-interest/headless.ts +2 -2
- package/src/plugins/builtin/short-interest/index.tsx +5 -5
- package/src/plugins/builtin/short-interest/pane.tsx +4 -4
- package/src/plugins/builtin/ticker-detail/pane.tsx +2 -2
- package/src/plugins/builtin/time-sales/client.ts +3 -3
- package/src/plugins/builtin/vol-surface/model.ts +1 -1
- package/src/plugins/builtin/volatility/model.ts +1 -1
- package/src/plugins/bundle.ts +2 -2
- package/src/plugins/catalog-manifest.ts +0 -1
- package/src/plugins/catalog-ui.ts +1 -1
- package/src/plugins/catalog.ts +0 -2
- package/src/plugins/host-link.ts +1 -1
- package/src/plugins/host-resolver.ts +1 -1
- package/src/plugins/loader.ts +6 -5
- package/src/plugins/registry/host-actions.ts +6 -1
- package/src/plugins/registry/index.ts +1 -0
- package/src/plugins/runtime/context.tsx +2 -0
- package/src/plugins/runtime/index.tsx +2 -0
- package/src/public/__snapshots__/public-api.test.ts.snap +0 -1
- package/src/public/market-data.ts +0 -7
- package/src/remote/controller-utils.ts +1 -1
- package/src/remote/controller.ts +27 -3
- package/src/remote/form.ts +20 -0
- package/src/remote/resources.ts +7 -0
- package/src/remote/schema.ts +25 -3
- package/src/remote/semantic-tree.tsx +15 -0
- package/src/remote/types.ts +2 -0
- package/src/renderers/browser/research-entry.ts +2 -2
- package/src/renderers/cloudflare/http-proxy.ts +157 -33
- package/src/renderers/cloudflare/proxy-session.ts +270 -0
- package/src/renderers/cloudflare/worker.ts +4 -1
- package/src/renderers/dom/desktop/controls.tsx +2 -1
- package/src/renderers/dom/dialog-host.tsx +17 -8
- package/src/renderers/dom/styles.css +4 -0
- package/src/renderers/electrobun/bun/application-menu/index.ts +4 -4
- package/src/renderers/electrobun/bun/desktop/backend.ts +7 -1
- package/src/renderers/electrobun/bun/desktop/initialization.ts +2 -2
- package/src/renderers/electrobun/bun/external-plugins.ts +1 -1
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +3 -6
- package/src/renderers/electrobun/view/cli-pane-shot-health.ts +3 -3
- package/src/renderers/opentui/dialog-host.tsx +14 -2
- package/src/renderers/opentui/start.tsx +2 -2
- package/src/renderers/opentui/terminal-media.ts +2 -2
- package/src/renderers/opentui/test-utils.tsx +9 -2
- package/src/renderers/opentui/toast-host.tsx +1 -1
- package/src/sources/gloomberb-cloud/index.ts +23 -24
- package/src/sources/gloomberb-cloud/news.ts +3 -3
- package/src/sources/history-retention.ts +6 -6
- package/src/sources/{yahoo-finance/symbols.ts → listing-symbols.ts} +16 -41
- package/src/sources/listing-target.ts +4 -4
- package/src/sources/provider-router/cache.ts +16 -6
- package/src/sources/provider-router/financials.ts +1 -1
- package/src/sources/provider-router/history.ts +3 -2
- package/src/state/app/bootstrap.ts +1 -1
- package/src/state/app/context/index.tsx +13 -0
- package/src/sync/core-contributors.ts +163 -16
- package/src/test-support/plugin-runtime.ts +1 -0
- package/src/tickers/instrument-kind.ts +1 -1
- package/src/tickers/open-target.ts +4 -4
- package/src/tickers/search/index.ts +3 -3
- package/src/tickers/search/ranking.ts +4 -4
- package/src/time-series/resolution.ts +1 -1
- package/src/time-series/resolve.ts +1 -1
- package/src/types/financials.ts +5 -5
- package/src/types/instrument.ts +1 -1
- package/src/types/plugin.ts +3 -3
- package/src/types/price-history.ts +1 -1
- package/src/ui/dialog-bridge.tsx +50 -0
- package/src/ui/dialog-context.ts +24 -0
- package/src/ui/dialog-stack.ts +47 -1
- package/src/ui/dialog.tsx +2 -10
- package/src/ui/host.tsx +6 -1
- package/src/ui/index.tsx +7 -2
- package/src/utils/latest-financial-period.ts +1 -1
- package/src/utils/plugin-proxy-hosts.json +1 -5
- package/src/utils/sec.ts +1 -1
- package/src/app/pane-template-dialog-wizard.tsx +0 -67
- package/src/components/command-bar/multi-select-picker.tsx +0 -225
- package/src/components/command-bar/multi-select-runtime.ts +0 -91
- package/src/components/command-bar/workflow/body.tsx +0 -164
- package/src/components/command-bar/workflow/field-row.tsx +0 -231
- package/src/components/command-bar/workflow/route-actions.ts +0 -235
- package/src/components/command-bar/workflow/runtime.ts +0 -247
- package/src/plugins/builtin/yahoo/index.ts +0 -38
- package/src/sources/yahoo-finance/chart-period.ts +0 -138
- package/src/sources/yahoo-finance/financials.ts +0 -370
- package/src/sources/yahoo-finance/history.ts +0 -150
- package/src/sources/yahoo-finance/http.ts +0 -119
- package/src/sources/yahoo-finance/mappers.ts +0 -549
- package/src/sources/yahoo-finance/names.ts +0 -28
- package/src/sources/yahoo-finance/options.ts +0 -190
- package/src/sources/yahoo-finance/quote-summary.ts +0 -176
- package/src/sources/yahoo-finance/requests.ts +0 -245
- package/src/sources/yahoo-finance/snapshots.ts +0 -336
- package/src/sources/yahoo-finance/types.ts +0 -198
- package/src/sources/yahoo-finance/yahoo-chart-interval.ts +0 -18
- package/src/sources/yahoo-finance.ts +0 -339
package/README.md
CHANGED
|
@@ -38,7 +38,7 @@ The desktop app and TUI share the command language and plugin system. The [brows
|
|
|
38
38
|
On **macOS (Apple Silicon)**:
|
|
39
39
|
|
|
40
40
|
```bash
|
|
41
|
-
brew install --cask
|
|
41
|
+
brew install --cask gloomberb
|
|
42
42
|
```
|
|
43
43
|
|
|
44
44
|
On **Windows 11**, [download the installer](https://github.com/gloom-sh/gloomberb/releases/latest/download/stable-win-x64-GloomberbSetup.exe). It supports x64, and ARM64 through x64 emulation.
|
|
@@ -117,7 +117,7 @@ When the app hits an uncaught error, a render crash, or a plugin that fails to l
|
|
|
117
117
|
|
|
118
118
|
The app also counts how often you open each function, from the command bar, a menu or a link in another pane, and which functions are on screen when a workspace is restored at launch. It sends each function's mnemonic (such as `DES` or `GP`) with those two counts, the surface, the app version and the operating system, a minute after the first count, then every 15 minutes, and when you quit. Functions from plugins other than the official gloom-sh ones are sent as `plugin`, so their names never leave your machine. The server adds your plan (signed out, Free or Pro); the counts are never tied to your account.
|
|
119
119
|
|
|
120
|
-
Neither contains anything from your workspace: no tickers, arguments, portfolios, watchlists, layouts, settings or queries. Both carry a random install id stored in
|
|
120
|
+
Neither contains anything from your workspace: no tickers, arguments, portfolios, watchlists, layouts, settings or queries. Both carry a random install id stored in `install-id` in the data folder, `~/.gloomberb` by default (in the browser, in local storage).
|
|
121
121
|
|
|
122
122
|
The usage setting also covers command bar searches. When you are signed in, a search you finish in the command bar (you pause typing or run something, never each keystroke) is stored with your account to improve search: its text, the AI suggestions it got and the result you picked. Searches are deleted with your account.
|
|
123
123
|
|
package/README.zh-CN.md
CHANGED
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
在 **macOS(Apple Silicon)** 上:
|
|
41
41
|
|
|
42
42
|
```bash
|
|
43
|
-
brew install --cask
|
|
43
|
+
brew install --cask gloomberb
|
|
44
44
|
```
|
|
45
45
|
|
|
46
46
|
在 **Windows 11** 上,[下载安装程序](https://github.com/gloom-sh/gloomberb/releases/latest/download/stable-win-x64-GloomberbSetup.exe)。支持 x64,也可通过 x64 仿真在 ARM64 上运行。
|
package/package.json
CHANGED
package/src/api-client/data.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { EarningsEvent } from "../types/data-provider";
|
|
2
|
+
import type { MarketDividendsPayload, MarketHeatmapResult, MarketHeatmapUniverseId, MarketMoversPayload } from "./market-discovery";
|
|
1
3
|
import type { DebtMaturitiesPayload } from "./debt-maturities";
|
|
2
4
|
import type { RevenueBreakdownPayload, RevenueBreakdownView } from "./revenue-breakdown";
|
|
3
5
|
import type { MnaDealPayload, MnaDealsParams, MnaDealsPayload } from "./mna";
|
|
@@ -39,11 +41,11 @@ import {
|
|
|
39
41
|
cloudJobsPath,
|
|
40
42
|
cloudJobsPostingsPath,
|
|
41
43
|
type CloudJobsPostingsParams,
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
cloudProxyStatementPath,
|
|
45
|
+
cloudFilingEventsPath,
|
|
46
|
+
cloudRiskReportPath,
|
|
47
|
+
cloudRiskReportsPath,
|
|
48
|
+
cloudProxyStatementsPath,
|
|
47
49
|
cloudExchangeRatePath,
|
|
48
50
|
cloudSec13FPath,
|
|
49
51
|
cloudSecFilingContentPath,
|
|
@@ -213,6 +215,31 @@ export class CloudDataApi {
|
|
|
213
215
|
);
|
|
214
216
|
}
|
|
215
217
|
|
|
218
|
+
getMarketEarningsCalendar(symbols: string[]): Promise<CloudMarketResponse<Array<Omit<EarningsEvent, "earningsDate" | "earningsCallDate"> & { earningsDate: string; earningsCallDate?: string | null }>>> {
|
|
219
|
+
return this.request(`/market/earnings-calendar?${new URLSearchParams({ symbols: symbols.join(",") })}`);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
getCloudArticleSummary(url: string): Promise<{ summary: string | null }> {
|
|
223
|
+
return this.request(`/news/article-summary?${new URLSearchParams({ url })}`);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
getMarketMovers(category: "day_gainers" | "day_losers" | "most_actives", count = 25, refresh = false): Promise<CloudMarketResponse<MarketMoversPayload>> {
|
|
227
|
+
const params = new URLSearchParams({ category, count: String(count), mode: refresh ? "refresh" : "cache-first" });
|
|
228
|
+
return this.request(`/market/movers?${params}`);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
getMarketTrending(count = 25): Promise<CloudMarketResponse<Array<{ symbol: string }>>> {
|
|
232
|
+
return this.request(`/market/trending?count=${encodeURIComponent(count)}`);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
getMarketHeatmap(universe: MarketHeatmapUniverseId, count = 80): Promise<CloudMarketResponse<MarketHeatmapResult>> {
|
|
236
|
+
return this.request(`/market/heatmap?${new URLSearchParams({ universe, count: String(count) })}`);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
getMarketDividends(symbol: string, exchange = ""): Promise<CloudMarketResponse<MarketDividendsPayload>> {
|
|
240
|
+
return this.requestMarketSymbol("/market/dividends", symbol, exchange);
|
|
241
|
+
}
|
|
242
|
+
|
|
216
243
|
/** Gainers, losers and most active, or the pre-market, after-hours and gap lists with a `side`. */
|
|
217
244
|
async getCloudMarketScreener<Category extends CloudMarketScreenerCategory | CloudSessionMoversCategory>(
|
|
218
245
|
category: Category,
|
|
@@ -521,7 +548,7 @@ export class CloudDataApi {
|
|
|
521
548
|
ticker: string,
|
|
522
549
|
): Promise<CloudProxyStatementListPayload> {
|
|
523
550
|
return this.request<CloudProxyStatementListPayload>(
|
|
524
|
-
|
|
551
|
+
cloudProxyStatementsPath(ticker),
|
|
525
552
|
);
|
|
526
553
|
}
|
|
527
554
|
|
|
@@ -530,7 +557,7 @@ export class CloudDataApi {
|
|
|
530
557
|
year: number,
|
|
531
558
|
): Promise<CloudProxyStatementPayload> {
|
|
532
559
|
return this.request<CloudProxyStatementPayload>(
|
|
533
|
-
|
|
560
|
+
cloudProxyStatementPath(ticker, year),
|
|
534
561
|
);
|
|
535
562
|
}
|
|
536
563
|
|
|
@@ -539,13 +566,13 @@ export class CloudDataApi {
|
|
|
539
566
|
limit?: number,
|
|
540
567
|
): Promise<{ ticker: string; events: CloudFilingEventPayload[] }> {
|
|
541
568
|
return this.request<{ ticker: string; events: CloudFilingEventPayload[] }>(
|
|
542
|
-
|
|
569
|
+
cloudFilingEventsPath(ticker, limit),
|
|
543
570
|
);
|
|
544
571
|
}
|
|
545
572
|
|
|
546
573
|
async getRiskReports(ticker: string): Promise<CloudRiskReportListPayload> {
|
|
547
574
|
return this.request<CloudRiskReportListPayload>(
|
|
548
|
-
|
|
575
|
+
cloudRiskReportsPath(ticker),
|
|
549
576
|
);
|
|
550
577
|
}
|
|
551
578
|
|
|
@@ -554,7 +581,7 @@ export class CloudDataApi {
|
|
|
554
581
|
year: number,
|
|
555
582
|
): Promise<CloudRiskReportPayload> {
|
|
556
583
|
return this.request<CloudRiskReportPayload>(
|
|
557
|
-
|
|
584
|
+
cloudRiskReportPath(ticker, year),
|
|
558
585
|
);
|
|
559
586
|
}
|
|
560
587
|
|
package/src/api-client/index.ts
CHANGED
|
@@ -677,6 +677,12 @@ class GloomApiClient {
|
|
|
677
677
|
getCloudQuote = this.data.getCloudQuote.bind(this.data);
|
|
678
678
|
getCloudQuotesBatch = this.data.getCloudQuotesBatch.bind(this.data);
|
|
679
679
|
getCloudWorldVenues = this.data.getCloudWorldVenues.bind(this.data);
|
|
680
|
+
getMarketEarningsCalendar = this.data.getMarketEarningsCalendar.bind(this.data);
|
|
681
|
+
getCloudArticleSummary = this.data.getCloudArticleSummary.bind(this.data);
|
|
682
|
+
getMarketMovers = this.data.getMarketMovers.bind(this.data);
|
|
683
|
+
getMarketTrending = this.data.getMarketTrending.bind(this.data);
|
|
684
|
+
getMarketHeatmap = this.data.getMarketHeatmap.bind(this.data);
|
|
685
|
+
getMarketDividends = this.data.getMarketDividends.bind(this.data);
|
|
680
686
|
getCloudMarketScreener = this.data.getCloudMarketScreener.bind(this.data);
|
|
681
687
|
getCloudOptionsChain = this.data.getCloudOptionsChain.bind(this.data);
|
|
682
688
|
getCloudFinancials = this.data.getCloudFinancials.bind(this.data);
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { CloudCorporateActionsPayload, CloudQuotePayload } from "./types";
|
|
2
|
+
|
|
3
|
+
export interface ScreenerQuote {
|
|
4
|
+
symbol: string;
|
|
5
|
+
name: string;
|
|
6
|
+
price: number | null;
|
|
7
|
+
change: number | null;
|
|
8
|
+
changePercent: number | null;
|
|
9
|
+
volume: number | null;
|
|
10
|
+
avgVolume: number | null;
|
|
11
|
+
volumeRatio: number | null; // volume / avgVolume
|
|
12
|
+
marketCap: number | undefined;
|
|
13
|
+
currency: string;
|
|
14
|
+
fiftyTwoWeekHigh: number | undefined;
|
|
15
|
+
fiftyTwoWeekLow: number | undefined;
|
|
16
|
+
dayHigh: number | undefined;
|
|
17
|
+
dayLow: number | undefined;
|
|
18
|
+
exchange: string;
|
|
19
|
+
lastUpdated?: number;
|
|
20
|
+
/** Session-fixed, so the price column reads its decimals from it rather than from each tick. */
|
|
21
|
+
previousClose?: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
export type MarketHeatmapUniverseId = "us-equity" | "us-etf";
|
|
26
|
+
type MarketHeatmapSource = "gloom";
|
|
27
|
+
type MarketHeatmapSizeKind = "market-cap" | "net-assets";
|
|
28
|
+
export interface MarketHeatmapAsset {
|
|
29
|
+
symbol: string;
|
|
30
|
+
name: string;
|
|
31
|
+
price: number;
|
|
32
|
+
change: number;
|
|
33
|
+
changePercent: number;
|
|
34
|
+
/**
|
|
35
|
+
* Whether the source actually carried a session change. `changePercent` keeps
|
|
36
|
+
* a numeric 0 for the shared screener row shape, so tiles must read this
|
|
37
|
+
* before showing a flat session that was really missing data.
|
|
38
|
+
*/
|
|
39
|
+
hasChange: boolean;
|
|
40
|
+
size: number | null;
|
|
41
|
+
sizeKind: MarketHeatmapSizeKind;
|
|
42
|
+
volume: number | null;
|
|
43
|
+
currency: string;
|
|
44
|
+
exchange: string;
|
|
45
|
+
sector: string | null;
|
|
46
|
+
industry: string | null;
|
|
47
|
+
marketState: string | null;
|
|
48
|
+
source: MarketHeatmapSource;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface MarketHeatmapResult {
|
|
52
|
+
stale?: boolean;
|
|
53
|
+
universe: MarketHeatmapUniverseId;
|
|
54
|
+
source: MarketHeatmapSource;
|
|
55
|
+
fetchedAt: number;
|
|
56
|
+
assets: MarketHeatmapAsset[];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
export interface MarketMoversPayload {
|
|
61
|
+
quotes: ScreenerQuote[];
|
|
62
|
+
source: "gloom";
|
|
63
|
+
stale: boolean;
|
|
64
|
+
asOf: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface DividendSummary {
|
|
68
|
+
trailingAnnualDividendRate: number | null;
|
|
69
|
+
trailingAnnualDividendYield: number | null;
|
|
70
|
+
forwardAnnualDividendRate: number | null;
|
|
71
|
+
payoutRatio: number | null;
|
|
72
|
+
exDividendDate: number | null;
|
|
73
|
+
dividendDate: number | null;
|
|
74
|
+
currency: string | null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface MarketDividendsPayload {
|
|
78
|
+
stale?: boolean;
|
|
79
|
+
actions: CloudCorporateActionsPayload | null;
|
|
80
|
+
quote: CloudQuotePayload | null;
|
|
81
|
+
summary: DividendSummary | null;
|
|
82
|
+
historyError?: string;
|
|
83
|
+
summaryError?: string;
|
|
84
|
+
}
|
package/src/api-client/paths.ts
CHANGED
|
@@ -311,30 +311,33 @@ export function cloudEarningsTranscriptPath(id: string): string {
|
|
|
311
311
|
return `/cloud/transcripts/${encodeURIComponent(id)}`;
|
|
312
312
|
}
|
|
313
313
|
|
|
314
|
-
/**
|
|
315
|
-
|
|
316
|
-
|
|
314
|
+
/**
|
|
315
|
+
* RISK, EXEC and EK are Pro: these reads need a verified Pro account. The same
|
|
316
|
+
* risk factors and pay are open under /public for the gloom.sh pages.
|
|
317
|
+
*/
|
|
318
|
+
export function cloudProxyStatementsPath(ticker: string): string {
|
|
319
|
+
return `/cloud/proxies/${encodeURIComponent(normalizeIssuerResearchTicker(ticker))}`;
|
|
317
320
|
}
|
|
318
321
|
|
|
319
|
-
export function
|
|
322
|
+
export function cloudFilingEventsPath(ticker: string, limit?: number): string {
|
|
320
323
|
const search = new URLSearchParams();
|
|
321
324
|
if (limit != null) search.set("limit", String(limit));
|
|
322
325
|
return appendQuery(
|
|
323
|
-
`/
|
|
326
|
+
`/cloud/events/${encodeURIComponent(normalizeIssuerResearchTicker(ticker))}`,
|
|
324
327
|
search,
|
|
325
328
|
);
|
|
326
329
|
}
|
|
327
330
|
|
|
328
|
-
export function
|
|
329
|
-
return `/
|
|
331
|
+
export function cloudRiskReportsPath(ticker: string): string {
|
|
332
|
+
return `/cloud/risks/${encodeURIComponent(normalizeIssuerResearchTicker(ticker))}`;
|
|
330
333
|
}
|
|
331
334
|
|
|
332
|
-
export function
|
|
333
|
-
return `/
|
|
335
|
+
export function cloudRiskReportPath(ticker: string, year: number): string {
|
|
336
|
+
return `/cloud/risks/${encodeURIComponent(normalizeIssuerResearchTicker(ticker))}/${year}`;
|
|
334
337
|
}
|
|
335
338
|
|
|
336
|
-
export function
|
|
337
|
-
return `/
|
|
339
|
+
export function cloudProxyStatementPath(ticker: string, year: number): string {
|
|
340
|
+
return `/cloud/proxies/${encodeURIComponent(normalizeIssuerResearchTicker(ticker))}/${year}`;
|
|
338
341
|
}
|
|
339
342
|
|
|
340
343
|
export function cloudSecFilingsPath(params: CloudSecFilingsParams): string {
|
|
@@ -17,6 +17,12 @@ import { SESSION_COOKIE_NAMES } from "./session-cookie";
|
|
|
17
17
|
|
|
18
18
|
const DEFAULT_API_URL = "https://api.gloom.sh";
|
|
19
19
|
const DEFAULT_MARKET_REQUEST_TIMEOUT_MS = 10_000;
|
|
20
|
+
const DEFAULT_RESEARCH_REQUEST_TIMEOUT_MS = 45_000;
|
|
21
|
+
// Research may fill missing sections after a primary read; quote/history reads remain latency bounded.
|
|
22
|
+
const RESEARCH_MARKET_PATHS = new Set([
|
|
23
|
+
"/market/dividends", "/market/short-interest", "/market/movers", "/market/trending",
|
|
24
|
+
"/market/heatmap", "/market/earnings-calendar",
|
|
25
|
+
]);
|
|
20
26
|
/** Local status for "this runtime cannot stream", never returned by the server. */
|
|
21
27
|
export const STREAMING_UNSUPPORTED_STATUS = 0;
|
|
22
28
|
|
|
@@ -140,6 +146,7 @@ export class CloudApiRequestTransport {
|
|
|
140
146
|
private cookieSessionMode = false;
|
|
141
147
|
private readonly fetchTransport: CloudApiFetchTransport | null;
|
|
142
148
|
private readonly marketRequestTimeoutMs: number;
|
|
149
|
+
private readonly researchRequestTimeoutMs: number;
|
|
143
150
|
private readonly connectionHealth: ConnectionHealthRegistry;
|
|
144
151
|
|
|
145
152
|
readonly baseUrl = getCloudApiBaseUrl();
|
|
@@ -154,6 +161,7 @@ export class CloudApiRequestTransport {
|
|
|
154
161
|
this.fetchTransport = options.fetchTransport ?? null;
|
|
155
162
|
this.marketRequestTimeoutMs =
|
|
156
163
|
options.marketRequestTimeoutMs ?? DEFAULT_MARKET_REQUEST_TIMEOUT_MS;
|
|
164
|
+
this.researchRequestTimeoutMs = options.marketRequestTimeoutMs ?? DEFAULT_RESEARCH_REQUEST_TIMEOUT_MS;
|
|
157
165
|
this.connectionHealth = options.connectionHealth ?? connectionHealth;
|
|
158
166
|
}
|
|
159
167
|
|
|
@@ -257,6 +265,8 @@ export class CloudApiRequestTransport {
|
|
|
257
265
|
return this.performRequest<T>(path, options, canApplySession);
|
|
258
266
|
}
|
|
259
267
|
|
|
268
|
+
const timeoutMs = RESEARCH_MARKET_PATHS.has(path.split("?")[0]!)
|
|
269
|
+
? this.researchRequestTimeoutMs : this.marketRequestTimeoutMs;
|
|
260
270
|
const controller = new AbortController();
|
|
261
271
|
const callerSignal = options?.signal;
|
|
262
272
|
const abortFromCaller = () => controller.abort(callerSignal?.reason);
|
|
@@ -273,8 +283,8 @@ export class CloudApiRequestTransport {
|
|
|
273
283
|
}, canApplySession);
|
|
274
284
|
return await withDeadline(
|
|
275
285
|
request,
|
|
276
|
-
|
|
277
|
-
`Cloud market request timed out after ${
|
|
286
|
+
timeoutMs,
|
|
287
|
+
`Cloud market request timed out after ${timeoutMs}ms: ${path}`,
|
|
278
288
|
(error) => controller.abort(error),
|
|
279
289
|
);
|
|
280
290
|
} finally {
|
package/src/api-client/tape.ts
CHANGED
|
@@ -11,7 +11,7 @@ export interface TapeQuote {
|
|
|
11
11
|
timestamp: string;
|
|
12
12
|
bid: number | null;
|
|
13
13
|
ask: number | null;
|
|
14
|
-
/**
|
|
14
|
+
/** Quote sizes are round lots. */
|
|
15
15
|
bidSize: number;
|
|
16
16
|
askSize: number;
|
|
17
17
|
bidExchange: string;
|
|
@@ -20,7 +20,7 @@ export interface TapeQuote {
|
|
|
20
20
|
tape: string;
|
|
21
21
|
}
|
|
22
22
|
export interface TapeSnapshot {
|
|
23
|
-
source: "
|
|
23
|
+
source: "Gloom Cloud";
|
|
24
24
|
symbol: string;
|
|
25
25
|
exchange: string;
|
|
26
26
|
access: "realtime" | "delayed";
|
package/src/api-client/types.ts
CHANGED
|
@@ -454,6 +454,7 @@ export interface CloudCdsHistoryResponse {
|
|
|
454
454
|
|
|
455
455
|
interface CloudShortInterestPointPayload {
|
|
456
456
|
settlementDate: string;
|
|
457
|
+
shortPercentFloat?: number | null;
|
|
457
458
|
sharesShort: number;
|
|
458
459
|
previousSharesShort: number | null;
|
|
459
460
|
averageDailyVolume: number | null;
|
|
@@ -463,6 +464,7 @@ interface CloudShortInterestPointPayload {
|
|
|
463
464
|
}
|
|
464
465
|
|
|
465
466
|
export interface CloudShortInterestPayload {
|
|
467
|
+
source?: "finra" | "gloom";
|
|
466
468
|
symbol: string;
|
|
467
469
|
issueName: string | null;
|
|
468
470
|
points: CloudShortInterestPointPayload[];
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { useCallback, useContext, type ReactNode } from "react";
|
|
2
|
+
import { RemoteUiRegistryProvider, useRemoteUiRegistry } from "../remote/semantic-tree";
|
|
3
|
+
import { AppContext, getEffectiveThemeId, useAppSelector } from "../state/app/context";
|
|
4
|
+
import { ThemeProvider } from "../theme/theme-context";
|
|
5
|
+
import { useRegisterDialogBridge } from "../ui/dialog-bridge";
|
|
6
|
+
import { KeybindingsProvider, useKeybindings } from "./keybindings";
|
|
7
|
+
|
|
8
|
+
function DialogTheme({ children }: { children: ReactNode }) {
|
|
9
|
+
const themeId = useAppSelector(getEffectiveThemeId);
|
|
10
|
+
return <ThemeProvider themeId={themeId}>{children}</ThemeProvider>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Gives every dialog what the app gives its panes: the store, the theme, the
|
|
15
|
+
* keybindings and the remote registry, so a form in a dialog reads state and
|
|
16
|
+
* registers nodes like one in the app. Renders nothing.
|
|
17
|
+
*/
|
|
18
|
+
export function AppDialogBridge() {
|
|
19
|
+
const store = useContext(AppContext);
|
|
20
|
+
const registry = useRemoteUiRegistry();
|
|
21
|
+
const keybindings = useKeybindings();
|
|
22
|
+
const bridge = useCallback((content: ReactNode) => {
|
|
23
|
+
const withKeybindings = <KeybindingsProvider value={keybindings}>{content}</KeybindingsProvider>;
|
|
24
|
+
const withRegistry = registry
|
|
25
|
+
? <RemoteUiRegistryProvider registry={registry}>{withKeybindings}</RemoteUiRegistryProvider>
|
|
26
|
+
: withKeybindings;
|
|
27
|
+
return store
|
|
28
|
+
? <AppContext value={store}><DialogTheme>{withRegistry}</DialogTheme></AppContext>
|
|
29
|
+
: withRegistry;
|
|
30
|
+
}, [keybindings, registry, store]);
|
|
31
|
+
useRegisterDialogBridge(bridge);
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
bringToFront,
|
|
7
7
|
findDockLeaf,
|
|
8
8
|
getDockedPaneIds,
|
|
9
|
+
isPaneDetached,
|
|
9
10
|
isPaneInLayout,
|
|
10
11
|
} from "../../layout/pane-manager";
|
|
11
12
|
import type { PluginRegistry } from "../../plugins/registry";
|
|
@@ -52,6 +53,8 @@ interface AppPaneRuntimeArgs {
|
|
|
52
53
|
dialog: DialogApi;
|
|
53
54
|
dispatch: Dispatch<AppAction>;
|
|
54
55
|
externalPlugins: readonly LoadedExternalPlugin[];
|
|
56
|
+
/** Desktop main window: raises a detached pane's own window. */
|
|
57
|
+
focusDetachedPane?: (paneId: string) => void;
|
|
55
58
|
isDetachedWindow: boolean;
|
|
56
59
|
notify: (body: string, options?: { type?: "info" | "success" | "error" }) => void;
|
|
57
60
|
persistConfig: (nextConfig: AppState["config"]) => void;
|
|
@@ -67,6 +70,7 @@ export function useAppPaneRuntime({
|
|
|
67
70
|
dialog,
|
|
68
71
|
dispatch,
|
|
69
72
|
externalPlugins,
|
|
73
|
+
focusDetachedPane,
|
|
70
74
|
isDetachedWindow,
|
|
71
75
|
notify,
|
|
72
76
|
persistConfig,
|
|
@@ -159,7 +163,9 @@ export function useAppPaneRuntime({
|
|
|
159
163
|
persistLayout(nextLayout, { pushHistory: false });
|
|
160
164
|
}
|
|
161
165
|
activatePane(paneId);
|
|
162
|
-
|
|
166
|
+
// Focus in this window's state alone would leave the pane's window behind this one.
|
|
167
|
+
if (isPaneDetached(nextLayout, paneId)) focusDetachedPane?.(paneId);
|
|
168
|
+
}, [activatePane, focusDetachedPane, persistLayout, state.config.layout]);
|
|
163
169
|
|
|
164
170
|
const placePaneInstance = useCallback((
|
|
165
171
|
instance: PaneInstanceConfig,
|
|
@@ -240,7 +246,6 @@ export function useAppPaneRuntime({
|
|
|
240
246
|
const { createPaneFromTemplate } = useAppPaneTemplateRuntime({
|
|
241
247
|
buildPaneInstance,
|
|
242
248
|
dataProvider,
|
|
243
|
-
dialog,
|
|
244
249
|
dispatch,
|
|
245
250
|
notify,
|
|
246
251
|
placePaneInstance,
|
|
@@ -32,7 +32,7 @@ export function useAppPaneSettingsRuntime({
|
|
|
32
32
|
stateRef,
|
|
33
33
|
tickerRepository,
|
|
34
34
|
}: UseAppPaneSettingsRuntimeOptions) {
|
|
35
|
-
const openPaneSettings = useCallback(async (paneId?: string) => {
|
|
35
|
+
const openPaneSettings = useCallback(async (paneId?: string, options?: { fieldKey?: string }) => {
|
|
36
36
|
const targetPaneId = paneId
|
|
37
37
|
? resolvePaneTarget(paneId)
|
|
38
38
|
: stateRef.current.focusedPaneId;
|
|
@@ -59,6 +59,7 @@ export function useAppPaneSettingsRuntime({
|
|
|
59
59
|
paneId={targetPaneId}
|
|
60
60
|
pluginRegistry={pluginRegistry}
|
|
61
61
|
applyFieldValue={applyFieldValue}
|
|
62
|
+
initialFieldKey={options?.fieldKey}
|
|
62
63
|
/>
|
|
63
64
|
),
|
|
64
65
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useCallback, type Dispatch } from "react";
|
|
2
2
|
import { getPaneTemplateDisplayLabel } from "../../components/command-bar/pane-templates/items";
|
|
3
3
|
import { createPaneTemplateOrThrow } from "../../components/command-bar/workflow/ops";
|
|
4
|
+
import { openFormModal } from "../../components/form-modal";
|
|
4
5
|
import type { AppTickerRepositoryPort } from "../../core/app-service-ports";
|
|
5
6
|
import type { PluginRegistry } from "../../plugins/registry";
|
|
6
7
|
import type { AppAction, AppState } from "../../state/app/context";
|
|
@@ -10,10 +11,7 @@ import type {
|
|
|
10
11
|
PaneDef,
|
|
11
12
|
PaneTemplateCreateOptions,
|
|
12
13
|
PaneTemplateInstanceConfig,
|
|
13
|
-
WizardStep,
|
|
14
14
|
} from "../../types/plugin";
|
|
15
|
-
import type { DialogApi } from "../../ui/dialog";
|
|
16
|
-
import { runPaneTemplateDialogWizard } from "../pane-template-dialog-wizard";
|
|
17
15
|
|
|
18
16
|
interface UseAppPaneTemplateRuntimeOptions {
|
|
19
17
|
buildPaneInstance: (paneType: string, options?: {
|
|
@@ -24,7 +22,6 @@ interface UseAppPaneTemplateRuntimeOptions {
|
|
|
24
22
|
instanceId?: string;
|
|
25
23
|
}) => PaneInstanceConfig | null;
|
|
26
24
|
dataProvider: DataProvider;
|
|
27
|
-
dialog: DialogApi;
|
|
28
25
|
dispatch: Dispatch<AppAction>;
|
|
29
26
|
notify: (body: string, options?: { type?: "info" | "success" | "error" }) => void;
|
|
30
27
|
placePaneInstance: (
|
|
@@ -40,7 +37,6 @@ interface UseAppPaneTemplateRuntimeOptions {
|
|
|
40
37
|
export function useAppPaneTemplateRuntime({
|
|
41
38
|
buildPaneInstance,
|
|
42
39
|
dataProvider,
|
|
43
|
-
dialog,
|
|
44
40
|
dispatch,
|
|
45
41
|
notify,
|
|
46
42
|
placePaneInstance,
|
|
@@ -48,38 +44,23 @@ export function useAppPaneTemplateRuntime({
|
|
|
48
44
|
stateRef,
|
|
49
45
|
tickerRepository,
|
|
50
46
|
}: UseAppPaneTemplateRuntimeOptions) {
|
|
51
|
-
const runPaneTemplateWizard = useCallback((steps: WizardStep[]) => (
|
|
52
|
-
runPaneTemplateDialogWizard(dialog, steps)
|
|
53
|
-
), [dialog]);
|
|
54
|
-
|
|
55
47
|
const createPaneFromTemplate = useCallback(async (templateId: string, options?: PaneTemplateCreateOptions) => {
|
|
56
48
|
const template = pluginRegistry.paneTemplates.get(templateId);
|
|
57
49
|
if (!template) return;
|
|
58
50
|
|
|
59
|
-
|
|
60
|
-
|
|
51
|
+
// A template that asks for settings asks in the same form the command bar
|
|
52
|
+
// opens, which creates the pane when it is sent.
|
|
53
|
+
const asksForSettings = !!template.wizard
|
|
61
54
|
&& template.wizard.length > 0
|
|
62
55
|
&& !options?.values
|
|
63
56
|
&& (!options?.arg || template.wizard.some((step) => step.type === "textarea"));
|
|
64
|
-
if (
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
step.key === template.shortcut?.argPlaceholder
|
|
68
|
-
? { ...step, defaultValue: options.arg }
|
|
69
|
-
: step
|
|
70
|
-
))
|
|
71
|
-
: template.wizard;
|
|
72
|
-
const values = await runPaneTemplateWizard(wizardSteps);
|
|
73
|
-
if (!values) return;
|
|
74
|
-
resolvedOptions = {
|
|
75
|
-
...options,
|
|
76
|
-
values,
|
|
77
|
-
arg: template.shortcut?.argPlaceholder ? values[template.shortcut.argPlaceholder] : options?.arg,
|
|
78
|
-
};
|
|
57
|
+
if (asksForSettings) {
|
|
58
|
+
openFormModal({ kind: "pane-template", templateId, arg: options?.arg, options });
|
|
59
|
+
return;
|
|
79
60
|
}
|
|
80
61
|
|
|
81
62
|
try {
|
|
82
|
-
await createPaneTemplateOrThrow(templateId,
|
|
63
|
+
await createPaneTemplateOrThrow(templateId, options, {
|
|
83
64
|
dataProvider,
|
|
84
65
|
tickerRepository,
|
|
85
66
|
pluginRegistry,
|
|
@@ -101,7 +82,6 @@ export function useAppPaneTemplateRuntime({
|
|
|
101
82
|
notify,
|
|
102
83
|
placePaneInstance,
|
|
103
84
|
pluginRegistry,
|
|
104
|
-
runPaneTemplateWizard,
|
|
105
85
|
stateRef,
|
|
106
86
|
tickerRepository,
|
|
107
87
|
]);
|
|
@@ -4,6 +4,9 @@ import {
|
|
|
4
4
|
createPaneTemplateOrThrow,
|
|
5
5
|
} from "../../components/command-bar/workflow/ops";
|
|
6
6
|
import type { AppTickerRepositoryPort } from "../../core/app-service-ports";
|
|
7
|
+
import { openFormModal } from "../../components/form-modal";
|
|
8
|
+
import { t } from "../../i18n";
|
|
9
|
+
import { openBrokerAddFlow } from "../../plugins/builtin/broker-manager/add-request";
|
|
7
10
|
import { getPanelFocusTarget } from "../../core/state/app/layout";
|
|
8
11
|
import { setLayoutManagerDispatch } from "../../plugins/builtin/layout-manager";
|
|
9
12
|
import { setMarketplaceHost } from "../../plugins/builtin/plugin-marketplace/store";
|
|
@@ -48,6 +51,7 @@ import type {
|
|
|
48
51
|
import type { TickerOpenTarget } from "../../tickers/open-target";
|
|
49
52
|
import { instrumentFromTicker } from "../../market-data/request-types";
|
|
50
53
|
import { tickerInstrumentLabel } from "../../tickers/instrument-label";
|
|
54
|
+
import { isDialogOpen } from "../../ui/dialog-stack";
|
|
51
55
|
import { stableStringify } from "../../utils/hash";
|
|
52
56
|
|
|
53
57
|
// Registry callbacks are rebound on renders. Request ownership must survive
|
|
@@ -70,7 +74,7 @@ interface BindAppPanePluginRegistryOptions {
|
|
|
70
74
|
externalPlugins: readonly LoadedExternalPlugin[];
|
|
71
75
|
focusVisiblePane: (paneId: string, layout?: LayoutConfig) => void;
|
|
72
76
|
isDetachedWindow: boolean;
|
|
73
|
-
openPaneSettings: (paneId?: string) => Promise<void>;
|
|
77
|
+
openPaneSettings: (paneId?: string, options?: { fieldKey?: string }) => Promise<void>;
|
|
74
78
|
openPinnedTicker: (rawSymbol: string, options?: PinTickerOptions) => Promise<void>;
|
|
75
79
|
persistConfig: (nextConfig: AppState["config"]) => void;
|
|
76
80
|
persistLayout: (layout: LayoutConfig, options?: { pushHistory?: boolean }) => void;
|
|
@@ -131,25 +135,43 @@ export function bindAppPanePluginRegistry({
|
|
|
131
135
|
if (paneId) dispatch({ type: "FOCUS_PANE", paneId });
|
|
132
136
|
},
|
|
133
137
|
switchTab: (tabId, paneId) => switchTickerResearchTab(tabId, paneId),
|
|
138
|
+
// The bar would open over a dialog without its keys, so it waits for none to be open.
|
|
134
139
|
openCommandBar: (query) => {
|
|
135
|
-
if (isDetachedWindow) return;
|
|
140
|
+
if (isDetachedWindow || isDialogOpen()) return;
|
|
136
141
|
dispatch({ type: "SET_COMMAND_BAR", open: true, query });
|
|
137
142
|
},
|
|
143
|
+
// Forms submit through the main window's state, so a detached window says where to go.
|
|
138
144
|
openPluginCommandWorkflow: (commandId) => {
|
|
139
|
-
if (isDetachedWindow)
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
145
|
+
if (isDetachedWindow) {
|
|
146
|
+
pluginRegistry.notify({ body: t("Open this from the main window."), type: "info" });
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
const command = pluginRegistry.commands.get(commandId);
|
|
150
|
+
if (!command?.wizard || command.wizard.length === 0) {
|
|
151
|
+
// Nothing to fill in: the bar opens, as it always has for such a command.
|
|
152
|
+
if (!isDialogOpen()) dispatch({ type: "SET_COMMAND_BAR", open: true, query: "" });
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
openFormModal({ kind: "plugin-command", commandId });
|
|
156
|
+
},
|
|
157
|
+
openBuiltInWorkflow: (actionId) => {
|
|
158
|
+
if (isDetachedWindow) {
|
|
159
|
+
pluginRegistry.notify({ body: t("Open this from the main window."), type: "info" });
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
// Profiles are added in the Brokers pane, not in a form.
|
|
163
|
+
if (actionId === "add-broker-account") {
|
|
164
|
+
openBrokerAddFlow(pluginRegistry);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
openFormModal({ kind: "builtin", actionId });
|
|
146
168
|
},
|
|
147
169
|
getLayout: () => stateRef.current.config.layout,
|
|
148
170
|
updateLayout: (layout) => {
|
|
149
171
|
if (isDetachedWindow) return;
|
|
150
172
|
persistLayout(layout);
|
|
151
173
|
},
|
|
152
|
-
openPaneSettings: (paneId) => { void openPaneSettings(paneId); },
|
|
174
|
+
openPaneSettings: (paneId, options) => { void openPaneSettings(paneId, options); },
|
|
153
175
|
showPane: (paneId) => {
|
|
154
176
|
if (isDetachedWindow) return;
|
|
155
177
|
showPane(paneId);
|
|
@@ -335,7 +357,7 @@ export function bindAppPanePluginRegistry({
|
|
|
335
357
|
toggleable: plugin.toggleable === true,
|
|
336
358
|
enabled: !disabled.has(plugin.id),
|
|
337
359
|
source: external ? "external" : "builtin",
|
|
338
|
-
...(external?.directory ? { directory: external.directory } : {}),
|
|
360
|
+
...(external?.directory ? { directory: external.directory, path: external.path } : {}),
|
|
339
361
|
...(external?.commit ? { commit: external.commit } : {}),
|
|
340
362
|
...(external?.linked ? { linked: true } : {}),
|
|
341
363
|
hasSetup,
|
|
@@ -358,7 +380,7 @@ export function bindAppPanePluginRegistry({
|
|
|
358
380
|
toggleable: true,
|
|
359
381
|
enabled: !disabled.has(entry.plugin.id),
|
|
360
382
|
source: "external",
|
|
361
|
-
...(entry.directory ? { directory: entry.directory } : {}),
|
|
383
|
+
...(entry.directory ? { directory: entry.directory, path: entry.path } : {}),
|
|
362
384
|
...(entry.commit ? { commit: entry.commit } : {}),
|
|
363
385
|
...(entry.linked ? { linked: true } : {}),
|
|
364
386
|
...(entry.unsupportedTarget ? { unsupportedTarget: entry.unsupportedTarget } : {}),
|