gloomberb 0.9.7 → 0.9.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/api-client/auth.ts +20 -0
- package/src/api-client/index.test.ts +3 -3
- package/src/api-client/index.ts +48 -6
- package/src/api-client/request.test.ts +63 -0
- package/src/api-client/request.ts +53 -5
- package/src/api-client/types.ts +45 -2
- package/src/app/pane-runtime/layout-placement.ts +0 -1
- package/src/app/runtime/desktop-deeplink.test.ts +87 -0
- package/src/app/runtime/desktop-deeplink.ts +496 -0
- package/src/app.tsx +34 -0
- package/src/brokers/account-cache.ts +2 -10
- package/src/brokers/broker-portfolio-sync.ts +0 -1
- package/src/brokers/broker-ticker-sync.ts +20 -16
- package/src/brokers/remote-broker-adapter.ts +3 -0
- package/src/capabilities/registry.test.ts +25 -0
- package/src/capabilities/registry.ts +22 -5
- package/src/cli/commands/automation.ts +1 -3
- package/src/cli/commands/command-utils.ts +0 -7
- package/src/cli/commands/overview.ts +2 -2
- package/src/cli/commands/plugins.ts +34 -17
- package/src/cli/index.ts +2 -2
- package/src/cli.test.ts +0 -157
- package/src/components/chart/bar-chart-renderer.test.ts +87 -12
- package/src/components/chart/bar-chart-renderer.ts +111 -55
- package/src/components/chart/comparison/renderer.ts +0 -1
- package/src/components/chart/comparison-stock-chart/render-output.ts +3 -8
- package/src/components/chart/comparison-stock-chart/view.tsx +0 -2
- package/src/components/chart/core/index.test.ts +0 -24
- package/src/components/chart/core/renderer.ts +0 -4
- package/src/components/chart/core/resolution.test.ts +0 -17
- package/src/components/chart/core/resolution.ts +0 -26
- package/src/components/chart/core/scroll.test.ts +0 -6
- package/src/components/chart/core/scroll.ts +0 -22
- package/src/components/chart/core/viewport.test.ts +2 -23
- package/src/components/chart/core/viewport.ts +0 -27
- package/src/components/chart/market-session.ts +1 -1
- package/src/components/chart/native/surface/hooks.ts +10 -3
- package/src/components/chart/static/bar-chart-surface.tsx +104 -20
- package/src/components/chart/stock-chart/data-runtime.ts +0 -1
- package/src/components/chart/stock-chart/footer.test.ts +65 -0
- package/src/components/chart/stock-chart/footer.ts +68 -13
- package/src/components/chart/stock-chart/resolved.tsx +18 -4
- package/src/components/chart/stock-chart/viewport/effects.ts +0 -3
- package/src/components/command-bar/helpers.test.ts +1 -80
- package/src/components/command-bar/helpers.ts +1 -36
- package/src/components/command-bar/pane-settings.ts +1 -1
- package/src/components/command-bar/pane-templates/items.ts +11 -3
- package/src/components/command-bar/panel/runtime.ts +0 -2
- package/src/components/command-bar/routes/root/results.ts +1 -1
- package/src/components/command-bar/routes/ticker-search/results.ts +0 -11
- package/src/components/command-bar/surface/index.test.tsx +52 -16
- package/src/components/command-bar/surface/index.tsx +0 -1
- package/src/components/command-bar/workflow/ops.ts +81 -20
- package/src/components/feed-data-table/stack-view.test.tsx +36 -130
- package/src/components/feed-data-table/stack-view.tsx +0 -1
- package/src/components/index.ts +1 -0
- package/src/components/layout/shell/index.test.tsx +2 -113
- package/src/components/layout/shell/index.tsx +0 -1
- package/src/components/layout/shell/menu.ts +0 -1
- package/src/components/layout/shell/terminal-pointer-runtime.ts +0 -1
- package/src/components/onboarding/onboarding-wizard.tsx +3 -3
- package/src/components/onboarding/wizard-keyboard.ts +2 -23
- package/src/components/price-selector-dialog.tsx +3 -3
- package/src/components/ticker/badge/text.tsx +0 -1
- package/src/components/toggle-list.tsx +29 -73
- package/src/components/ui/button.tsx +4 -1
- package/src/components/ui/checkbox.tsx +76 -0
- package/src/components/ui/choice-dialog.tsx +15 -3
- package/src/components/ui/frame.tsx +1 -1
- package/src/components/ui/index.ts +2 -0
- package/src/components/ui/message-composer.tsx +4 -0
- package/src/components/ui/native-select.tsx +4 -2
- package/src/components/ui/page-stack-view.tsx +1 -1
- package/src/components/ui/ui.test.tsx +0 -78
- package/src/core/state/app/layout-reducer.ts +0 -1
- package/src/data/config/layout.ts +3 -3
- package/src/data/resource-store.ts +6 -0
- package/src/data/sqlite/cache.test.ts +5 -0
- package/src/data/ticker-store.ts +0 -7
- package/src/market-data/coordinator/auxiliary.ts +1 -44
- package/src/market-data/coordinator/entries.ts +0 -1
- package/src/market-data/coordinator/events.test.ts +49 -0
- package/src/market-data/coordinator/events.ts +25 -4
- package/src/market-data/coordinator/index.test.ts +223 -10
- package/src/market-data/coordinator/index.ts +41 -21
- package/src/market-data/coordinator/quotes.ts +13 -11
- package/src/market-data/coordinator/subscriptions.test.ts +1 -0
- package/src/market-data/hooks.tsx +17 -13
- package/src/market-data/market/freshness.ts +58 -1
- package/src/market-data/market/status.ts +19 -1
- package/src/market-data/query-store.ts +0 -4
- package/src/market-data/quotes/freshness.test.ts +49 -1
- package/src/market-data/quotes/freshness.ts +8 -0
- package/src/market-data/quotes/resolution.test.ts +185 -0
- package/src/market-data/quotes/resolution.ts +96 -10
- package/src/market-data/request-types.test.ts +61 -1
- package/src/market-data/request-types.ts +42 -8
- package/src/market-data/result-types.ts +0 -11
- package/src/market-data/selectors.ts +1 -5
- package/src/news/aggregator.ts +5 -1
- package/src/pane-settings.test.ts +0 -18
- package/src/plugins/builtin/account-management/footer.ts +2 -5
- package/src/plugins/builtin/account-management/form-components.tsx +175 -59
- package/src/plugins/builtin/account-management/keyboard.ts +32 -2
- package/src/plugins/builtin/account-management/model.test.ts +99 -4
- package/src/plugins/builtin/account-management/model.ts +259 -23
- package/src/plugins/builtin/account-management/pane.tsx +784 -155
- package/src/plugins/builtin/broker-manager/index.test.tsx +0 -32
- package/src/plugins/builtin/buildout/cells.tsx +1 -1
- package/src/plugins/builtin/buildout/detail/satellite-images.tsx +1 -1
- package/src/plugins/builtin/buildout/detail/ui.tsx +0 -1
- package/src/plugins/builtin/buildout/format.ts +2 -11
- package/src/plugins/builtin/chat/chat.test.tsx +127 -1
- package/src/plugins/builtin/chat/content/channel-navigation.ts +1 -21
- package/src/plugins/builtin/chat/content/composer-cursor.ts +29 -0
- package/src/plugins/builtin/chat/content/composer-runtime.ts +22 -24
- package/src/plugins/builtin/chat/content/composer.tsx +84 -1
- package/src/plugins/builtin/chat/content/index.tsx +153 -16
- package/src/plugins/builtin/chat/content/layout-metrics.ts +10 -1
- package/src/plugins/builtin/chat/content/mentions.test.ts +74 -0
- package/src/plugins/builtin/chat/content/mentions.ts +88 -0
- package/src/plugins/builtin/chat/content/new-dm-dialog.tsx +264 -0
- package/src/plugins/builtin/chat/content/shortcuts.ts +47 -1
- package/src/plugins/builtin/chat/content/snapshot.ts +7 -0
- package/src/plugins/builtin/chat/content/transcript.tsx +0 -5
- package/src/plugins/builtin/chat/controller/index.ts +0 -10
- package/src/plugins/builtin/chat/controller.test.ts +5 -5
- package/src/plugins/builtin/chat/message/profile-popover.test.tsx +36 -0
- package/src/plugins/builtin/chat/message/profile-popover.tsx +124 -20
- package/src/plugins/builtin/chat/sidebar.test.tsx +83 -6
- package/src/plugins/builtin/chat/sidebar.tsx +26 -2
- package/src/plugins/builtin/chat/test-harness.tsx +22 -12
- package/src/plugins/builtin/cloud/plugin.tsx +8 -1
- package/src/plugins/builtin/cloud-tweets/pane.tsx +0 -1
- package/src/plugins/builtin/congress-trades/model.ts +2 -7
- package/src/plugins/builtin/congress-trades/pane.tsx +0 -1
- package/src/plugins/builtin/correlation/index.tsx +4 -1
- package/src/plugins/builtin/correlation/relationship/controls.tsx +8 -2
- package/src/plugins/builtin/correlation/relationship/model.ts +22 -2
- package/src/plugins/builtin/correlation/relationship/pane.tsx +9 -3
- package/src/plugins/builtin/earnings/index.tsx +0 -9
- package/src/plugins/builtin/econ/index.tsx +1 -5
- package/src/plugins/builtin/help/index.tsx +2 -2
- package/src/plugins/builtin/holders/pane.tsx +0 -5
- package/src/plugins/builtin/insider/index.tsx +1 -8
- package/src/plugins/builtin/kelly-sizer/index.test.tsx +0 -26
- package/src/plugins/builtin/kelly-sizer/index.tsx +0 -2
- package/src/plugins/builtin/market-movers/index.tsx +0 -2
- package/src/plugins/builtin/news/index.tsx +0 -1
- package/src/plugins/builtin/news/wire/news/table.tsx +0 -11
- package/src/plugins/builtin/options/view.test.tsx +1 -38
- package/src/plugins/builtin/plugin-groups.ts +17 -3
- package/src/plugins/builtin/portfolio-list/column-values.ts +15 -8
- package/src/plugins/builtin/portfolio-list/index.test.ts +52 -25
- package/src/plugins/builtin/portfolio-list/metrics.test.ts +44 -7
- package/src/plugins/builtin/portfolio-list/pane/data.test.ts +54 -0
- package/src/plugins/builtin/portfolio-list/pane/data.ts +50 -3
- package/src/plugins/builtin/portfolio-list/pane/index.test.tsx +314 -16
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +11 -4
- package/src/plugins/builtin/portfolio-list/pane/streaming.ts +83 -24
- package/src/plugins/builtin/sec/filing-documents.ts +0 -11
- package/src/plugins/builtin/sec/index.tsx +0 -2
- package/src/plugins/builtin/substack/article-detail.tsx +1 -1
- package/src/plugins/builtin/thirteenf/api.ts +0 -15
- package/src/plugins/builtin/thirteenf/pane.tsx +1 -3
- package/src/plugins/builtin/ticker-detail/data-panes/fundamental-graph/content.tsx +42 -6
- package/src/plugins/builtin/ticker-detail/data-panes/fundamental-graph/model.ts +415 -64
- package/src/plugins/builtin/ticker-detail/data-panes/fundamental-graph/settings.ts +23 -2
- package/src/plugins/builtin/ticker-detail/data-panes/fundamental-graph/types.ts +8 -1
- package/src/plugins/builtin/ticker-detail/data-panes/fundamental-graph.tsx +3 -1
- package/src/plugins/builtin/ticker-detail/data-panes.test.ts +95 -1
- package/src/plugins/builtin/ticker-detail/financials/tab.tsx +0 -7
- package/src/plugins/builtin/ticker-detail/index.tsx +2 -0
- package/src/plugins/builtin/ticker-detail/quote-monitor/index.test.tsx +5 -34
- package/src/plugins/builtin/world-indices/index.tsx +0 -4
- package/src/plugins/builtin/world-indices/model.ts +0 -7
- package/src/plugins/ibkr/account-cache.ts +1 -1
- package/src/plugins/ibkr/gateway/market-data.ts +12 -5
- package/src/plugins/ibkr/gateway/service/index.test.ts +31 -0
- package/src/plugins/ibkr/portfolio-performance.ts +1 -1
- package/src/plugins/ibkr/trade/utils.ts +1 -7
- package/src/plugins/loader.ts +2 -1
- package/src/plugins/prediction-markets/detail.test.tsx +0 -34
- package/src/plugins/registry/context.ts +15 -0
- package/src/plugins/registry/contributions.ts +22 -11
- package/src/plugins/registry/index.test.ts +44 -0
- package/src/plugins/registry/index.ts +75 -26
- package/src/remote/controller.ts +1 -7
- package/src/remote/json-patch.ts +15 -1
- package/src/remote/server.ts +16 -6
- package/src/renderers/electrobun/bun/application-menu/index.ts +1 -1
- package/src/renderers/electrobun/bun/core-capabilities.ts +2 -0
- package/src/renderers/electrobun/bun/desktop/http-fetch.test.ts +14 -0
- package/src/renderers/electrobun/bun/desktop/http-fetch.ts +8 -0
- package/src/renderers/electrobun/bun/desktop/initialization.ts +2 -1
- package/src/renderers/electrobun/bun/index.ts +42 -0
- package/src/renderers/electrobun/shared/protocol.ts +5 -0
- package/src/renderers/electrobun/view/backend-rpc.ts +29 -0
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -0
- package/src/renderers/electrobun/view/data-table/dom.ts +0 -1
- package/src/renderers/electrobun/view/desktop/controls.tsx +135 -4
- package/src/renderers/electrobun/view/desktop/list-view.tsx +38 -25
- package/src/renderers/electrobun/view/desktop-deeplink-bridge.ts +10 -0
- package/src/renderers/electrobun/view/host/box.tsx +0 -2
- package/src/renderers/electrobun/view/host/mouse.ts +0 -11
- package/src/renderers/electrobun/view/host/scroll-box.tsx +1 -2
- package/src/renderers/electrobun/view/host/text.tsx +1 -2
- package/src/renderers/electrobun/view/http-fetch.ts +15 -2
- package/src/renderers/electrobun/view/main.tsx +3 -0
- package/src/renderers/electrobun/view/remote/asset-data-client.ts +9 -18
- package/src/renderers/electrobun/view/remote/capability-invoker.test.ts +50 -0
- package/src/renderers/electrobun/view/remote/capability-invoker.ts +36 -0
- package/src/renderers/electrobun/view/ui-host.tsx +2 -0
- package/src/renderers/opentui/host.tsx +11 -3
- package/src/renderers/opentui/input-host.tsx +5 -1
- package/src/sources/gloomberb-cloud/index.test.ts +0 -72
- package/src/sources/gloomberb-cloud/index.ts +1 -30
- package/src/sources/gloomberb-cloud/news.ts +0 -12
- package/src/sources/provider-router/batches.ts +11 -3
- package/src/sources/provider-router/cached-financials.test.ts +123 -0
- package/src/sources/provider-router/financial-routes.ts +77 -5
- package/src/sources/provider-router/financials.test.ts +49 -0
- package/src/sources/provider-router/financials.ts +40 -3
- package/src/sources/provider-router/index.test.ts +314 -0
- package/src/sources/provider-router/primary.ts +17 -3
- package/src/sources/provider-router/search.ts +5 -0
- package/src/sources/provider-router/streaming.ts +6 -1
- package/src/sources/provider-router/supplemental.ts +4 -3
- package/src/sources/sec-edgar.test.ts +42 -0
- package/src/sources/sec-edgar.ts +1 -2
- package/src/sources/yahoo-finance/history.ts +5 -1
- package/src/sources/yahoo-finance/mappers.test.ts +29 -0
- package/src/sources/yahoo-finance/mappers.ts +2 -1
- package/src/sources/yahoo-finance/options.ts +59 -14
- package/src/sources/yahoo-finance/quote-summary.ts +4 -1
- package/src/sources/yahoo-finance/requests.ts +2 -1
- package/src/sources/yahoo-finance/snapshots.ts +13 -2
- package/src/sources/yahoo-finance.test.ts +40 -21
- package/src/sources/yahoo-finance.ts +19 -10
- package/src/state/app/context/index.test.tsx +0 -81
- package/src/state/app/context/selector.test.tsx +6 -2
- package/src/state/hooks/quote-streaming.test.ts +14 -1
- package/src/state/hooks/quote-streaming.ts +5 -4
- package/src/sync/controller.test.ts +31 -0
- package/src/sync/controller.ts +300 -0
- package/src/sync/core-contributors.test.ts +251 -0
- package/src/sync/core-contributors.ts +400 -0
- package/src/sync/profile-analytics.ts +39 -0
- package/src/sync/react.ts +53 -0
- package/src/sync/types.ts +77 -0
- package/src/test-support/data-provider.ts +0 -1
- package/src/types/desktop-deeplink.ts +7 -0
- package/src/types/plugin.ts +3 -0
- package/src/ui/host.tsx +15 -1
- package/src/ui/index.tsx +2 -0
- package/src/updater.test.ts +0 -21
- package/src/updater.ts +20 -16
- package/src/utils/async-deadline.ts +26 -0
- package/src/utils/exchanges.test.ts +11 -1
- package/src/utils/exchanges.ts +5 -1
- package/src/utils/selection-clipboard.ts +2 -2
- package/src/version.ts +1 -1
- package/src/components/layout/pane/header.test.tsx +0 -39
- package/src/plugins/builtin/chat/channels.test.ts +0 -28
- package/src/plugins/builtin/chat/index.tsx +0 -4
- package/src/plugins/builtin/cloud-tweets/index.ts +0 -1
- package/src/plugins/builtin/earnings/index.test.ts +0 -12
- package/src/plugins/builtin/help/index.test.tsx +0 -242
- package/src/plugins/builtin/substack/article-detail.test.tsx +0 -10
- package/src/renderers/electrobun/bun/application-menu/index.test.ts +0 -21
- package/src/renderers/electrobun/bun/window/focus.test.ts +0 -35
- package/src/renderers/electrobun/view/host/mouse.test.ts +0 -37
- package/src/renderers/electrobun/view/host/text.test.ts +0 -22
- package/src/renderers/opentui/dialog-host.test.tsx +0 -44
- /package/src/{plugins/ibkr → utils}/hash.ts +0 -0
|
@@ -3,7 +3,7 @@ import type { PluginRegistry } from "../../plugins/registry";
|
|
|
3
3
|
import { fuzzyFilter } from "../../utils/fuzzy-search";
|
|
4
4
|
import type { ResultItem } from "./list/model";
|
|
5
5
|
import type { CommandBarRoute, CommandBarWorkflowRoute } from "./workflow/types";
|
|
6
|
-
import { summarizePaneSettingValue } from "
|
|
6
|
+
import { summarizePaneSettingValue } from "../pane-settings-dialog/value";
|
|
7
7
|
|
|
8
8
|
type NotifyFn = (body: string, options?: { type?: "info" | "success" | "error" }) => void;
|
|
9
9
|
|
|
@@ -139,6 +139,14 @@ export function buildPaneTemplateItem(options: {
|
|
|
139
139
|
.join(" ")
|
|
140
140
|
: null;
|
|
141
141
|
const arg = options.createOptions?.arg;
|
|
142
|
+
const searchText = [
|
|
143
|
+
options.template.keywords?.join(" ") || "",
|
|
144
|
+
displayLabel,
|
|
145
|
+
options.template.label,
|
|
146
|
+
options.template.paneId,
|
|
147
|
+
shortcutLabel || "",
|
|
148
|
+
pluginName || "",
|
|
149
|
+
].filter(Boolean).join(" ");
|
|
142
150
|
|
|
143
151
|
const action = () => {
|
|
144
152
|
if (
|
|
@@ -163,7 +171,7 @@ export function buildPaneTemplateItem(options: {
|
|
|
163
171
|
kind: "action",
|
|
164
172
|
right: options.showShortcut ? options.template.shortcut?.prefix : undefined,
|
|
165
173
|
shortcutQuery: options.template.shortcut?.prefix,
|
|
166
|
-
searchText
|
|
174
|
+
searchText,
|
|
167
175
|
action,
|
|
168
176
|
};
|
|
169
177
|
}
|
|
@@ -187,7 +195,7 @@ export function buildPaneShortcutItems(options: {
|
|
|
187
195
|
}));
|
|
188
196
|
|
|
189
197
|
return options.filterQuery
|
|
190
|
-
? fuzzyFilter(items, options.filterQuery, (item) => `${item.label} ${item.
|
|
198
|
+
? fuzzyFilter(items, options.filterQuery, (item) => `${item.label} ${item.searchText || ""} ${item.detail} ${item.right || ""}`)
|
|
191
199
|
: items;
|
|
192
200
|
}
|
|
193
201
|
|
|
@@ -201,6 +209,6 @@ export function buildNonShortcutPaneTemplateItems(options: {
|
|
|
201
209
|
.map((template) => options.createItem(template, { category: "Panes" }));
|
|
202
210
|
|
|
203
211
|
return options.filterQuery
|
|
204
|
-
? fuzzyFilter(items, options.filterQuery, (item) => `${item.label} ${item.
|
|
212
|
+
? fuzzyFilter(items, options.filterQuery, (item) => `${item.label} ${item.searchText || ""} ${item.detail} ${item.right || ""}`)
|
|
205
213
|
: items;
|
|
206
214
|
}
|
|
@@ -37,7 +37,6 @@ interface CommandBarPanelRuntimeOptions {
|
|
|
37
37
|
applyThemePreview: (themeId: string | null) => void;
|
|
38
38
|
cellHeightPx: number;
|
|
39
39
|
cellWidthPx: number;
|
|
40
|
-
clearThemePreview: (themeId: string | null | undefined) => void;
|
|
41
40
|
closeAll: (options?: { revertThemePreview?: boolean }) => void;
|
|
42
41
|
commitTheme: (themeId: string) => void;
|
|
43
42
|
committedThemeId: string;
|
|
@@ -92,7 +91,6 @@ export function useCommandBarPanelRuntime({
|
|
|
92
91
|
applyThemePreview,
|
|
93
92
|
cellHeightPx,
|
|
94
93
|
cellWidthPx,
|
|
95
|
-
clearThemePreview,
|
|
96
94
|
closeAll,
|
|
97
95
|
commitTheme,
|
|
98
96
|
committedThemeId,
|
|
@@ -196,7 +196,7 @@ export function buildRootResultModel(options: RootResultModelOptions): RootResul
|
|
|
196
196
|
...tickerActionItems(),
|
|
197
197
|
...pluginCommandItems(),
|
|
198
198
|
];
|
|
199
|
-
items.push(...fuzzyFilter(allItems, rootQuery, (item) => `${item.label} ${item.
|
|
199
|
+
items.push(...fuzzyFilter(allItems, rootQuery, (item) => `${item.label} ${item.searchText || ""} ${item.detail} ${item.right || ""}`));
|
|
200
200
|
}
|
|
201
201
|
|
|
202
202
|
return { items, initialIdx };
|
|
@@ -24,17 +24,6 @@ export function normalizeCommandTickerSearchText(value: string): string {
|
|
|
24
24
|
return value.trim().toUpperCase().replace(/[^A-Z0-9]+/g, "");
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
export function isLikelyPlainTickerSearch(query: string): boolean {
|
|
28
|
-
const trimmed = query.trim();
|
|
29
|
-
if (!trimmed || /\s/.test(trimmed)) return false;
|
|
30
|
-
if (!/^[A-Za-z0-9.^=\-/]+$/.test(trimmed)) return false;
|
|
31
|
-
|
|
32
|
-
const compact = normalizeCommandTickerSearchText(trimmed);
|
|
33
|
-
if (compact.length < 2) return false;
|
|
34
|
-
if (compact.length <= 6) return true;
|
|
35
|
-
return /[.^=\-/]/.test(trimmed) && compact.length <= 10;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
27
|
function isExactTickerResultMatch(item: ResultItem, query: string): boolean {
|
|
39
28
|
if (item.kind !== "ticker" && item.kind !== "search") return false;
|
|
40
29
|
const normalizedQuery = normalizeCommandTickerSearchText(query);
|
|
@@ -6,6 +6,7 @@ import type { CommandDef, CommandShortcutArgContext, PaneTemplateCreateOptions,
|
|
|
6
6
|
import {
|
|
7
7
|
CommandBarHarness,
|
|
8
8
|
createCommandBarTestControls,
|
|
9
|
+
emitKeypress,
|
|
9
10
|
expectSingleBackControl,
|
|
10
11
|
makeDataProvider,
|
|
11
12
|
makeTicker,
|
|
@@ -26,6 +27,11 @@ type MutableCommandRegistry = {
|
|
|
26
27
|
commands: ReadonlyMap<string, CommandDef>;
|
|
27
28
|
};
|
|
28
29
|
|
|
30
|
+
type MutablePaneRegistry = {
|
|
31
|
+
panes: ReadonlyMap<string, unknown>;
|
|
32
|
+
paneTemplates: ReadonlyMap<string, unknown>;
|
|
33
|
+
};
|
|
34
|
+
|
|
29
35
|
const DEFAULT_ALERT_OPTIONS = [
|
|
30
36
|
{ label: "Above", value: "above" },
|
|
31
37
|
{ label: "Below", value: "below" },
|
|
@@ -70,23 +76,11 @@ function registerAlertCommand(
|
|
|
70
76
|
});
|
|
71
77
|
}
|
|
72
78
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
width: 80,
|
|
77
|
-
height: 24,
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
await testSetup.renderOnce();
|
|
81
|
-
|
|
82
|
-
const frame = testSetup.captureCharFrame();
|
|
83
|
-
expect(frame).toContain("Commands");
|
|
84
|
-
expect(frame).not.toContain("Tickers");
|
|
85
|
-
expect(frame).toContain("Panes");
|
|
86
|
-
expect(frame).toContain("Portfolio");
|
|
87
|
-
expect(frame).toContain("Help");
|
|
88
|
-
});
|
|
79
|
+
function mutablePaneRegistryMap(map: ReadonlyMap<string, unknown>): Map<string, unknown> {
|
|
80
|
+
return map as Map<string, unknown>;
|
|
81
|
+
}
|
|
89
82
|
|
|
83
|
+
describe("CommandBar", () => {
|
|
90
84
|
test("keeps generic command filtering separate from ticker search", async () => {
|
|
91
85
|
const searchQueries: string[] = [];
|
|
92
86
|
testSetup = await testRender(<CommandBarHarness
|
|
@@ -129,6 +123,48 @@ describe("CommandBar", () => {
|
|
|
129
123
|
expect(testSetup.captureCharFrame()).not.toContain("Commands");
|
|
130
124
|
});
|
|
131
125
|
|
|
126
|
+
test("shows one account management result when searching profile", async () => {
|
|
127
|
+
const created: Array<{ templateId: string; options?: PaneTemplateCreateOptions }> = [];
|
|
128
|
+
|
|
129
|
+
testSetup = await testRender(<CommandBarHarness
|
|
130
|
+
query="profile"
|
|
131
|
+
live
|
|
132
|
+
configurePluginRegistry={(pluginRegistry) => {
|
|
133
|
+
const registry = pluginRegistry as MutablePaneRegistry;
|
|
134
|
+
mutablePaneRegistryMap(registry.panes).set("account-management", {
|
|
135
|
+
id: "account-management",
|
|
136
|
+
name: "Account Management",
|
|
137
|
+
component: () => null,
|
|
138
|
+
defaultPosition: "right",
|
|
139
|
+
defaultMode: "floating",
|
|
140
|
+
});
|
|
141
|
+
mutablePaneRegistryMap(registry.paneTemplates).set("account-management-pane", {
|
|
142
|
+
id: "account-management-pane",
|
|
143
|
+
paneId: "account-management",
|
|
144
|
+
label: "Account Management",
|
|
145
|
+
description: "Edit your Gloom Cloud profile, password, and public portfolio sharing settings",
|
|
146
|
+
keywords: ["account", "profile", "cloud", "acm", "password", "settings"],
|
|
147
|
+
shortcut: { prefix: "ACM" },
|
|
148
|
+
});
|
|
149
|
+
pluginRegistry.createPaneFromTemplateAsyncFn = async (templateId, options) => {
|
|
150
|
+
created.push({ templateId, options });
|
|
151
|
+
};
|
|
152
|
+
}}
|
|
153
|
+
/>, {
|
|
154
|
+
width: 80,
|
|
155
|
+
height: 24,
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
await testSetup.renderOnce();
|
|
159
|
+
const frame = await waitForFrameToContain("Account Management");
|
|
160
|
+
expect(frame).not.toMatch(/\n\s*Profile\s*(?:\n|$)/);
|
|
161
|
+
expect(frame.indexOf("Account Management")).toBeLessThan(frame.indexOf("Add Broker Account"));
|
|
162
|
+
|
|
163
|
+
await emitKeypress(testSetup, { name: "return", sequence: "\r" });
|
|
164
|
+
|
|
165
|
+
expect(created).toEqual([{ templateId: "account-management-pane", options: undefined }]);
|
|
166
|
+
});
|
|
167
|
+
|
|
132
168
|
test("shows theme picker rows and commits a filtered light theme", async () => {
|
|
133
169
|
testSetup = await testRender(<CommandBarHarness query="TH light" live />, {
|
|
134
170
|
width: 80,
|
|
@@ -6,11 +6,22 @@ import { formatTickerListInput } from "../../../tickers/list";
|
|
|
6
6
|
import { updatePaneInstance, setPaneSettings } from "../../../pane-settings";
|
|
7
7
|
import { TICKER_RESEARCH_PANE_ID } from "../../../types/config";
|
|
8
8
|
import { cleanPortfolioPaneSettings, resolvePortfolioPaneCollectionId } from "../../../plugins/builtin/portfolio-list/settings";
|
|
9
|
+
import {
|
|
10
|
+
DEFAULT_RELATIONSHIP_SECOND_SYMBOL,
|
|
11
|
+
RELATIONSHIP_GRAPH_PANE_ID,
|
|
12
|
+
buildRelationshipGraphPaneTitle,
|
|
13
|
+
} from "../../../plugins/builtin/correlation/relationship/model";
|
|
9
14
|
import {
|
|
10
15
|
buildComparisonChartPaneTitle,
|
|
11
16
|
COMPARISON_CHART_PANE_ID,
|
|
12
17
|
MIN_COMPARISON_CHART_SYMBOLS,
|
|
13
18
|
} from "../../../plugins/builtin/comparison-chart";
|
|
19
|
+
import {
|
|
20
|
+
FUNDAMENTAL_GRAPH_PANE_ID,
|
|
21
|
+
graphKindFromSettings,
|
|
22
|
+
graphShortcutForKind,
|
|
23
|
+
graphTemplateTitle,
|
|
24
|
+
} from "../../../plugins/builtin/ticker-detail/data-panes/fundamental-graph/settings";
|
|
14
25
|
import { buildQuoteMonitorPaneTitle } from "../../../plugins/builtin/ticker-detail/settings";
|
|
15
26
|
import { getPaneTemplateDisplayLabel } from "../pane-templates/items";
|
|
16
27
|
import {
|
|
@@ -54,6 +65,30 @@ interface ApplyPaneSettingDeps extends SharedWorkflowDeps {
|
|
|
54
65
|
persistLayout: (layout: LayoutConfig, options?: { pushHistory?: boolean }) => void;
|
|
55
66
|
}
|
|
56
67
|
|
|
68
|
+
function updateTickerListPane(
|
|
69
|
+
layout: LayoutConfig,
|
|
70
|
+
targetId: string,
|
|
71
|
+
options: {
|
|
72
|
+
title: string;
|
|
73
|
+
symbols: readonly string[];
|
|
74
|
+
primarySymbol?: string;
|
|
75
|
+
settings?: Record<string, unknown>;
|
|
76
|
+
},
|
|
77
|
+
): LayoutConfig {
|
|
78
|
+
const symbols = [...options.symbols];
|
|
79
|
+
return updatePaneInstance(layout, targetId, (instance) => ({
|
|
80
|
+
...instance,
|
|
81
|
+
title: options.title,
|
|
82
|
+
...(options.primarySymbol ? { binding: { kind: "fixed", symbol: options.primarySymbol } as PaneBinding } : {}),
|
|
83
|
+
settings: {
|
|
84
|
+
...(instance.settings ?? {}),
|
|
85
|
+
symbols,
|
|
86
|
+
symbolsText: formatTickerListInput(symbols),
|
|
87
|
+
...(options.settings ?? {}),
|
|
88
|
+
},
|
|
89
|
+
}));
|
|
90
|
+
}
|
|
91
|
+
|
|
57
92
|
async function resolvePaneTemplateOptions(
|
|
58
93
|
template: PaneTemplateDef,
|
|
59
94
|
options: PaneTemplateCreateOptions | undefined,
|
|
@@ -180,19 +215,50 @@ export async function applyPaneSettingFieldValue(
|
|
|
180
215
|
const rawQuery = typeof value === "string" ? value.trim() : "";
|
|
181
216
|
const symbols = await resolveTickerListInput(rawQuery, null, deps);
|
|
182
217
|
const primarySymbol = symbols[0]!;
|
|
183
|
-
const
|
|
184
|
-
|
|
185
|
-
const nextLayout = updatePaneInstance(state.config.layout, targetId, (instance) => ({
|
|
186
|
-
...instance,
|
|
218
|
+
const nextLayout = updateTickerListPane(state.config.layout, targetId, {
|
|
187
219
|
title: buildQuoteMonitorPaneTitle(symbols),
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
220
|
+
symbols,
|
|
221
|
+
primarySymbol,
|
|
222
|
+
settings: { symbol: primarySymbol },
|
|
223
|
+
});
|
|
224
|
+
deps.persistLayout(nextLayout, { pushHistory: shouldPushHistory });
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (descriptor.pane.paneId === FUNDAMENTAL_GRAPH_PANE_ID && field.key === "symbolsText") {
|
|
229
|
+
const rawInput = typeof value === "string" ? value : "";
|
|
230
|
+
const symbols = await resolveTickerListInput(
|
|
231
|
+
rawInput,
|
|
232
|
+
descriptor.context.activeCollectionId,
|
|
233
|
+
deps,
|
|
234
|
+
);
|
|
235
|
+
const primarySymbol = symbols[0]!;
|
|
236
|
+
const chartKind = graphKindFromSettings(descriptor.context.settings, "fundamental");
|
|
237
|
+
const nextLayout = updateTickerListPane(state.config.layout, targetId, {
|
|
238
|
+
title: graphTemplateTitle(graphShortcutForKind(chartKind), symbols),
|
|
239
|
+
symbols,
|
|
240
|
+
primarySymbol,
|
|
241
|
+
});
|
|
242
|
+
deps.persistLayout(nextLayout, { pushHistory: shouldPushHistory });
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
if (descriptor.pane.paneId === RELATIONSHIP_GRAPH_PANE_ID && field.key === "symbolsText") {
|
|
247
|
+
const rawInput = typeof value === "string" ? value : "";
|
|
248
|
+
const symbols = await resolveTickerListInput(
|
|
249
|
+
rawInput,
|
|
250
|
+
descriptor.context.activeCollectionId,
|
|
251
|
+
deps,
|
|
252
|
+
);
|
|
253
|
+
if (symbols.length > 2) {
|
|
254
|
+
throw new Error("Enter one or two tickers.");
|
|
255
|
+
}
|
|
256
|
+
const pair: [string, string] = [symbols[0]!, symbols[1] ?? DEFAULT_RELATIONSHIP_SECOND_SYMBOL];
|
|
257
|
+
const nextLayout = updateTickerListPane(state.config.layout, targetId, {
|
|
258
|
+
title: buildRelationshipGraphPaneTitle(pair),
|
|
259
|
+
symbols: pair,
|
|
260
|
+
primarySymbol: pair[0],
|
|
261
|
+
});
|
|
196
262
|
deps.persistLayout(nextLayout, { pushHistory: shouldPushHistory });
|
|
197
263
|
return;
|
|
198
264
|
}
|
|
@@ -207,15 +273,10 @@ export async function applyPaneSettingFieldValue(
|
|
|
207
273
|
if (symbols.length < MIN_COMPARISON_CHART_SYMBOLS) {
|
|
208
274
|
throw new Error(`Enter at least ${MIN_COMPARISON_CHART_SYMBOLS} tickers.`);
|
|
209
275
|
}
|
|
210
|
-
const nextLayout =
|
|
211
|
-
...instance,
|
|
276
|
+
const nextLayout = updateTickerListPane(state.config.layout, targetId, {
|
|
212
277
|
title: buildComparisonChartPaneTitle(symbols),
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
symbols,
|
|
216
|
-
symbolsText: formatTickerListInput(symbols),
|
|
217
|
-
},
|
|
218
|
-
}));
|
|
278
|
+
symbols,
|
|
279
|
+
});
|
|
219
280
|
deps.persistLayout(nextLayout, { pushHistory: shouldPushHistory });
|
|
220
281
|
return;
|
|
221
282
|
}
|
|
@@ -1,148 +1,54 @@
|
|
|
1
|
-
import { afterEach,
|
|
2
|
-
import { act
|
|
1
|
+
import { afterEach, expect, test } from "bun:test";
|
|
2
|
+
import { act } from "react";
|
|
3
3
|
import { testRender } from "../../renderers/opentui/test-utils";
|
|
4
4
|
import { AppContext, PaneInstanceProvider, createInitialState } from "../../state/app/context";
|
|
5
5
|
import { createDefaultConfig } from "../../types/config";
|
|
6
|
-
import {
|
|
7
|
-
FeedDataTableStackView,
|
|
8
|
-
type FeedDataTableItem,
|
|
9
|
-
} from "./stack-view";
|
|
10
6
|
import { Box, Text } from "../../ui";
|
|
7
|
+
import { FeedDataTableStackView } from "./stack-view";
|
|
11
8
|
|
|
12
9
|
let testSetup: Awaited<ReturnType<typeof testRender>> | undefined;
|
|
13
|
-
let rootKeyHits = 0;
|
|
14
|
-
|
|
15
|
-
const items: FeedDataTableItem[] = [
|
|
16
|
-
{
|
|
17
|
-
id: "1",
|
|
18
|
-
eyebrow: "Reuters",
|
|
19
|
-
title:
|
|
20
|
-
"Long headline with enough words to prove the table truncates cleanly",
|
|
21
|
-
timestamp: new Date("2024-08-01T12:00:00Z"),
|
|
22
|
-
preview: "Preview text with a little more color.",
|
|
23
|
-
detailTitle: "Long headline with enough words",
|
|
24
|
-
detailMeta: ["Reuters", "Published Aug 1, 2024"],
|
|
25
|
-
detailBody:
|
|
26
|
-
"This body should stay readable when the pane opens the detail page.",
|
|
27
|
-
detailNote: "https://example.com/story",
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
id: "2",
|
|
31
|
-
eyebrow: "10-Q",
|
|
32
|
-
title: "10-Q filing",
|
|
33
|
-
timestamp: new Date("2024-08-02T12:00:00Z"),
|
|
34
|
-
preview: "Quarterly report",
|
|
35
|
-
detailTitle: "10-Q filing",
|
|
36
|
-
detailMeta: ["Filed Aug 2, 2024"],
|
|
37
|
-
detailBody: "Quarterly report details.",
|
|
38
|
-
},
|
|
39
|
-
];
|
|
40
10
|
|
|
41
11
|
afterEach(async () => {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
testSetup!.renderer.destroy();
|
|
45
|
-
});
|
|
46
|
-
testSetup = undefined;
|
|
47
|
-
}
|
|
48
|
-
rootKeyHits = 0;
|
|
12
|
+
await act(async () => testSetup?.renderer.destroy());
|
|
13
|
+
testSetup = undefined;
|
|
49
14
|
});
|
|
50
15
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
withRootControls = false,
|
|
55
|
-
}: {
|
|
56
|
-
width: number;
|
|
57
|
-
height: number;
|
|
58
|
-
withRootControls?: boolean;
|
|
59
|
-
}) {
|
|
60
|
-
const [selectedIdx, setSelectedIdx] = useState(0);
|
|
61
|
-
|
|
62
|
-
const state = createInitialState(
|
|
63
|
-
createDefaultConfig("/tmp/gloomberb-detail-data-table-test"),
|
|
64
|
-
);
|
|
65
|
-
|
|
66
|
-
return (
|
|
67
|
-
<AppContext value={{ state, dispatch: () => {} }}>
|
|
68
|
-
<PaneInstanceProvider paneId="portfolio-list:main">
|
|
69
|
-
<FeedDataTableStackView
|
|
70
|
-
width={width}
|
|
71
|
-
height={height}
|
|
72
|
-
focused
|
|
73
|
-
items={items}
|
|
74
|
-
selectedIdx={selectedIdx}
|
|
75
|
-
onSelect={setSelectedIdx}
|
|
76
|
-
rootBefore={withRootControls ? (
|
|
77
|
-
<Box height={1}>
|
|
78
|
-
<Text>Feed controls</Text>
|
|
79
|
-
</Box>
|
|
80
|
-
) : undefined}
|
|
81
|
-
onRootKeyDown={withRootControls ? (event) => {
|
|
82
|
-
if (event.name !== "f") return false;
|
|
83
|
-
rootKeyHits += 1;
|
|
84
|
-
return true;
|
|
85
|
-
} : undefined}
|
|
86
|
-
sourceLabel="Source"
|
|
87
|
-
titleLabel="Headline"
|
|
88
|
-
/>
|
|
89
|
-
</PaneInstanceProvider>
|
|
90
|
-
</AppContext>
|
|
91
|
-
);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
async function renderSettled() {
|
|
16
|
+
test("delegates root key handling", async () => {
|
|
17
|
+
let keyHits = 0;
|
|
18
|
+
const state = createInitialState(createDefaultConfig("/tmp/gloomberb-feed-table-test"));
|
|
95
19
|
await act(async () => {
|
|
96
|
-
await
|
|
97
|
-
|
|
20
|
+
testSetup = await testRender(
|
|
21
|
+
<AppContext value={{ state, dispatch: () => {} }}>
|
|
22
|
+
<PaneInstanceProvider paneId="portfolio-list:main">
|
|
23
|
+
<FeedDataTableStackView
|
|
24
|
+
width={80}
|
|
25
|
+
height={12}
|
|
26
|
+
focused
|
|
27
|
+
items={[]}
|
|
28
|
+
selectedIdx={0}
|
|
29
|
+
onSelect={() => {}}
|
|
30
|
+
rootBefore={<Box height={1}><Text>Feed controls</Text></Box>}
|
|
31
|
+
onRootKeyDown={(event) => {
|
|
32
|
+
if (event.name !== "f") return false;
|
|
33
|
+
keyHits += 1;
|
|
34
|
+
return true;
|
|
35
|
+
}}
|
|
36
|
+
/>
|
|
37
|
+
</PaneInstanceProvider>
|
|
38
|
+
</AppContext>,
|
|
39
|
+
{ width: 80, height: 12 },
|
|
40
|
+
);
|
|
41
|
+
await testSetup.renderOnce();
|
|
98
42
|
});
|
|
99
|
-
}
|
|
100
43
|
|
|
101
|
-
async function emitKeypress(event: { name?: string; sequence?: string }) {
|
|
102
44
|
await act(async () => {
|
|
103
|
-
testSetup!.renderer.keyInput.emit("keypress", {
|
|
104
|
-
|
|
105
|
-
meta: false,
|
|
106
|
-
|
|
107
|
-
shift: false,
|
|
108
|
-
eventType: "press",
|
|
109
|
-
repeated: false,
|
|
110
|
-
preventDefault: () => {},
|
|
111
|
-
stopPropagation: () => {},
|
|
112
|
-
...event,
|
|
113
|
-
} as any);
|
|
114
|
-
await testSetup!.renderOnce();
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
describe("FeedDataTableStackView", () => {
|
|
119
|
-
test("renders a DataTable list by default", async () => {
|
|
120
|
-
testSetup = await testRender(<Harness width={90} height={16} />, {
|
|
121
|
-
width: 90,
|
|
122
|
-
height: 16,
|
|
45
|
+
(testSetup!.renderer.keyInput as any).emit("keypress", {
|
|
46
|
+
name: "f", sequence: "f", eventType: "press",
|
|
47
|
+
ctrl: false, meta: false, option: false, shift: false, repeated: false,
|
|
48
|
+
preventDefault() {}, stopPropagation() {},
|
|
123
49
|
});
|
|
124
|
-
|
|
125
|
-
await renderSettled();
|
|
126
|
-
const frame = testSetup.captureCharFrame();
|
|
127
|
-
|
|
128
|
-
expect(frame).toContain("Time");
|
|
129
|
-
expect(frame).toContain("Source");
|
|
130
|
-
expect(frame).toContain("Headline");
|
|
131
|
-
expect(frame).toContain("10-Q filing");
|
|
132
|
-
expect(frame).not.toContain("j/k move");
|
|
133
|
-
expect(frame).not.toContain("Quarterly report details.");
|
|
50
|
+
await testSetup!.renderOnce();
|
|
134
51
|
});
|
|
135
52
|
|
|
136
|
-
|
|
137
|
-
testSetup = await testRender(<Harness width={90} height={16} withRootControls />, {
|
|
138
|
-
width: 90,
|
|
139
|
-
height: 16,
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
await renderSettled();
|
|
143
|
-
expect(testSetup.captureCharFrame()).toContain("Feed controls");
|
|
144
|
-
|
|
145
|
-
await emitKeypress({ name: "f", sequence: "f" });
|
|
146
|
-
expect(rootKeyHits).toBe(1);
|
|
147
|
-
});
|
|
53
|
+
expect(keyHits).toBe(1);
|
|
148
54
|
});
|
package/src/components/index.ts
CHANGED
|
@@ -25,6 +25,7 @@ export { PaneFooterScope, usePaneFooter } from "./layout/pane/footer";
|
|
|
25
25
|
export type { PaneFooterSegment, PaneHint } from "./layout/pane/footer";
|
|
26
26
|
export { useExternalLinkFooter } from "./use-external-link-footer";
|
|
27
27
|
export { Button } from "./ui/button";
|
|
28
|
+
export { Checkbox } from "./ui/checkbox";
|
|
28
29
|
export { ConfirmDialog } from "./ui/confirm-dialog";
|
|
29
30
|
export { ChoiceDialog } from "./ui/choice-dialog";
|
|
30
31
|
export type { ChoiceDialogChoice } from "./ui/choice-dialog";
|