gloomberb 0.4.1 → 0.5.0
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/package.json +1 -1
- package/src/app.tsx +168 -65
- package/src/cli/commands/ticker.ts +45 -15
- package/src/cli/helpers.ts +4 -2
- package/src/cli/registry.test.ts +42 -35
- package/src/cli.test.ts +4 -2
- package/src/components/chart/chart-control-hint.tsx +39 -0
- package/src/components/chart/chart-controller.test.ts +110 -0
- package/src/components/chart/chart-controller.ts +364 -2
- package/src/components/chart/chart-data.ts +177 -29
- package/src/components/chart/chart-indicator-selector.tsx +53 -0
- package/src/components/chart/chart-pane-settings.ts +20 -0
- package/src/components/chart/chart-renderer.ts +220 -30
- package/src/components/chart/chart-resolution.test.ts +67 -0
- package/src/components/chart/chart-resolution.ts +74 -4
- package/src/components/chart/chart-scroll.test.ts +69 -0
- package/src/components/chart/chart-scroll.ts +104 -0
- package/src/components/chart/chart-types.ts +12 -0
- package/src/components/chart/chart-viewport.test.ts +5 -1
- package/src/components/chart/chart-viewport.ts +1 -1
- package/src/components/chart/chart.test.ts +249 -10
- package/src/components/chart/comparison-chart-renderer.test.ts +71 -1
- package/src/components/chart/comparison-chart-renderer.ts +40 -3
- package/src/components/chart/comparison-stock-chart.tsx +218 -123
- package/src/components/chart/indicators/bands.test.ts +50 -0
- package/src/components/chart/indicators/bands.ts +29 -0
- package/src/components/chart/indicators/moving-averages.test.ts +54 -0
- package/src/components/chart/indicators/moving-averages.ts +42 -0
- package/src/components/chart/indicators/options.test.ts +32 -0
- package/src/components/chart/indicators/options.ts +107 -0
- package/src/components/chart/indicators/oscillators.test.ts +79 -0
- package/src/components/chart/indicators/oscillators.ts +92 -0
- package/src/components/chart/indicators/types.ts +36 -0
- package/src/components/chart/native/chart-rasterizer.ts +51 -0
- package/src/components/chart/native/kitty.test.ts +68 -0
- package/src/components/chart/stock-chart-renderer-switch.test.tsx +740 -9
- package/src/components/chart/stock-chart.test.ts +239 -0
- package/src/components/chart/stock-chart.tsx +2257 -372
- package/src/components/command-bar/command-bar.test.tsx +337 -5
- package/src/components/command-bar/command-bar.tsx +292 -120
- package/src/components/command-bar/helpers.ts +1 -1
- package/src/components/command-bar/root-shortcuts.ts +33 -4
- package/src/components/command-bar/view-model.test.ts +3 -3
- package/src/components/command-bar/view-model.ts +4 -4
- package/src/components/command-bar/workflow-ops.ts +10 -0
- package/src/components/layout/header.tsx +2 -1
- package/src/components/layout/shell.test.tsx +186 -27
- package/src/components/layout/shell.tsx +5 -4
- package/src/components/layout/status-bar.test.tsx +16 -7
- package/src/components/layout/status-bar.tsx +4 -1
- package/src/components/markdown-editor.tsx +1 -0
- package/src/components/pane-settings-dialog.tsx +13 -152
- package/src/components/pane-template-wizard.tsx +1 -0
- package/src/components/price-selector-dialog.tsx +12 -7
- package/src/components/ticker-badge-text.test.tsx +50 -0
- package/src/components/ticker-badge-text.tsx +17 -2
- package/src/components/ticker-badge.tsx +2 -2
- package/src/components/ticker-list-table.tsx +54 -1
- package/src/components/toggle-list.tsx +15 -2
- package/src/components/ui/data-table.tsx +60 -3
- package/src/components/ui/external-link.tsx +48 -11
- package/src/components/ui/fields.tsx +2 -1
- package/src/components/ui/index.ts +8 -1
- package/src/components/ui/multi-select-chips.tsx +69 -0
- package/src/components/ui/multi-select-dialog.tsx +267 -0
- package/src/components/ui/multi-select.ts +78 -0
- package/src/components/ui/ui.test.tsx +343 -1
- package/src/data/plugin-state-store.ts +30 -19
- package/src/data/resource-store.ts +133 -103
- package/src/data/session-store.ts +19 -12
- package/src/data/sqlite-cache.test.ts +37 -2
- package/src/data/sqlite-database.ts +8 -2
- package/src/data/sqlite-retry.test.ts +63 -0
- package/src/data/sqlite-retry.ts +66 -0
- package/src/data/ticker-store.ts +29 -18
- package/src/index.tsx +6 -1
- package/src/market-data/coordinator.test.ts +114 -5
- package/src/market-data/coordinator.ts +70 -1
- package/src/market-data/hooks.test.tsx +73 -2
- package/src/market-data/hooks.tsx +16 -4
- package/src/notifications/app-notifier.test.ts +177 -0
- package/src/notifications/app-notifier.ts +241 -0
- package/src/pane-settings.test.ts +2 -0
- package/src/plugins/builtin/ai/index.test.tsx +1 -1
- package/src/plugins/builtin/ai/screener-pane.test.tsx +2 -0
- package/src/plugins/builtin/ai/screener-pane.tsx +1 -0
- package/src/plugins/builtin/ai/ticker-context.ts +3 -2
- package/src/plugins/builtin/alerts/alert-engine.test.ts +90 -0
- package/src/plugins/builtin/alerts/alert-engine.ts +55 -0
- package/src/plugins/builtin/alerts/index.test.tsx +357 -0
- package/src/plugins/builtin/alerts/index.tsx +519 -0
- package/src/plugins/builtin/alerts/types.ts +14 -0
- package/src/plugins/builtin/analytics/index.test.tsx +300 -0
- package/src/plugins/builtin/analytics/index.tsx +775 -0
- package/src/plugins/builtin/analytics/metrics.test.ts +125 -0
- package/src/plugins/builtin/analytics/metrics.ts +155 -0
- package/src/plugins/builtin/ask-ai.test.tsx +2 -0
- package/src/plugins/builtin/chat-controller.test.ts +62 -18
- package/src/plugins/builtin/chat-controller.ts +23 -12
- package/src/plugins/builtin/chat.test.tsx +715 -4
- package/src/plugins/builtin/chat.tsx +415 -119
- package/src/plugins/builtin/comparison-chart.test.tsx +97 -57
- package/src/plugins/builtin/comparison-chart.tsx +1 -2
- package/src/plugins/builtin/correlation/compute.test.ts +147 -0
- package/src/plugins/builtin/correlation/compute.ts +115 -0
- package/src/plugins/builtin/correlation/index.tsx +385 -0
- package/src/plugins/builtin/correlation/plugin.test.ts +44 -0
- package/src/plugins/builtin/correlation/settings.test.ts +34 -0
- package/src/plugins/builtin/correlation/settings.ts +95 -0
- package/src/plugins/builtin/debug.tsx +36 -50
- package/src/plugins/builtin/earnings/earnings-cache.test.ts +181 -0
- package/src/plugins/builtin/earnings/earnings-cache.ts +136 -0
- package/src/plugins/builtin/earnings/earnings-data.test.ts +59 -0
- package/src/plugins/builtin/earnings/earnings-data.ts +50 -0
- package/src/plugins/builtin/earnings/index.tsx +337 -0
- package/src/plugins/builtin/econ/calendar-source.test.ts +219 -0
- package/src/plugins/builtin/econ/calendar-source.ts +121 -0
- package/src/plugins/builtin/econ/fred-client.test.ts +63 -0
- package/src/plugins/builtin/econ/fred-client.ts +79 -0
- package/src/plugins/builtin/econ/fred-series-map.ts +88 -0
- package/src/plugins/builtin/econ/index.tsx +999 -0
- package/src/plugins/builtin/econ/types.ts +13 -0
- package/src/plugins/builtin/fred-settings.ts +10 -0
- package/src/plugins/builtin/fx-matrix/index.tsx +178 -0
- package/src/plugins/builtin/fx-matrix/pairs.ts +30 -0
- package/src/plugins/builtin/help.test.tsx +1 -5
- package/src/plugins/builtin/help.tsx +1 -16
- package/src/plugins/builtin/insider/index.tsx +417 -0
- package/src/plugins/builtin/insider/insider-data.test.ts +55 -0
- package/src/plugins/builtin/insider/insider-data.ts +49 -0
- package/src/plugins/builtin/layout-manager.tsx +24 -16
- package/src/plugins/builtin/market-movers/index.tsx +573 -0
- package/src/plugins/builtin/market-movers/screener.test.ts +143 -0
- package/src/plugins/builtin/market-movers/screener.ts +105 -0
- package/src/plugins/builtin/options.tsx +4 -3
- package/src/plugins/builtin/portfolio-list/cli/commands.ts +11 -6
- package/src/plugins/builtin/portfolio-list/command-bar.ts +6 -3
- package/src/plugins/builtin/portfolio-list/header.tsx +3 -2
- package/src/plugins/builtin/portfolio-list/metrics.ts +22 -11
- package/src/plugins/builtin/portfolio-list/pane.tsx +3 -9
- package/src/plugins/builtin/portfolio-list/settings.ts +9 -0
- package/src/plugins/builtin/portfolio-list/table.tsx +3 -0
- package/src/plugins/builtin/portfolio-list.test.tsx +3 -1
- package/src/plugins/builtin/portfolio-metrics.test.ts +13 -1
- package/src/plugins/builtin/sec.tsx +114 -7
- package/src/plugins/builtin/sectors/index.tsx +359 -0
- package/src/plugins/builtin/sectors/sector-data.ts +18 -0
- package/src/plugins/builtin/ticker-detail/chart-tab.tsx +75 -13
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +316 -80
- package/src/plugins/builtin/ticker-detail/quote-monitor.tsx +4 -6
- package/src/plugins/builtin/ticker-detail-chart-tab-switch.test.tsx +17 -12
- package/src/plugins/builtin/ticker-detail.test.tsx +3 -3
- package/src/plugins/builtin/world-indices/index.tsx +410 -0
- package/src/plugins/builtin/world-indices/indices.ts +52 -0
- package/src/plugins/builtin/yield-curve/index.tsx +242 -0
- package/src/plugins/builtin/yield-curve/treasury-data.test.ts +212 -0
- package/src/plugins/builtin/yield-curve/treasury-data.ts +107 -0
- package/src/plugins/catalog.ts +22 -0
- package/src/plugins/gridlock-notification.ts +15 -0
- package/src/plugins/ibkr/__snapshots__/trade-tab.test.tsx.snap +5 -5
- package/src/plugins/ibkr/index.test.tsx +1 -1
- package/src/plugins/ibkr/index.tsx +1 -1
- package/src/plugins/ibkr/trade-tab.tsx +23 -5
- package/src/plugins/ibkr/trade-utils.test.ts +1 -1
- package/src/plugins/ibkr/trade-utils.ts +7 -6
- package/src/plugins/ibkr/trading-pane.tsx +8 -7
- package/src/plugins/plugin-runtime.test.tsx +2 -0
- package/src/plugins/plugin-runtime.tsx +10 -0
- package/src/plugins/prediction-markets/controller-data.ts +8 -0
- package/src/plugins/prediction-markets/detail/shared.tsx +7 -6
- package/src/plugins/prediction-markets/plugin.test.tsx +48 -1
- package/src/plugins/prediction-markets/services/fetch.ts +13 -7
- package/src/plugins/prediction-markets/services/polymarket-adapter.ts +29 -11
- package/src/plugins/prediction-markets/services/polymarket-ws.ts +20 -0
- package/src/plugins/prediction-markets/test-helpers.tsx +2 -0
- package/src/plugins/registry.ts +22 -13
- package/src/sources/provider-router.test.ts +3 -2
- package/src/sources/sec-edgar.ts +13 -1
- package/src/sources/yahoo-finance.ts +75 -1
- package/src/state/app-context-selector.test.tsx +17 -1
- package/src/state/app-context.test.tsx +24 -0
- package/src/state/app-context.tsx +29 -6
- package/src/theme/colors.ts +5 -0
- package/src/theme/themes.ts +25 -0
- package/src/types/config.test.ts +107 -0
- package/src/types/config.ts +30 -1
- package/src/types/data-provider.ts +13 -0
- package/src/types/plugin.ts +35 -1
- package/src/utils/format.test.ts +11 -1
- package/src/utils/format.ts +86 -8
- package/src/utils/inline-content-tokenizer.test.ts +22 -0
- package/src/utils/inline-content-tokenizer.ts +76 -0
- package/src/utils/link-tokenizer.test.ts +27 -0
- package/src/utils/link-tokenizer.ts +93 -0
- package/src/utils/market-format.test.ts +109 -0
- package/src/utils/market-format.ts +299 -0
- package/src/utils/market-status.ts +3 -2
- package/src/utils/selection-clipboard.test.ts +43 -0
- package/src/utils/selection-clipboard.ts +88 -0
- package/src/utils/terminal-input-reset.test.ts +50 -0
- package/src/utils/terminal-input-reset.ts +24 -0
- package/src/utils/throttled-fetch.test.ts +145 -0
- package/src/utils/throttled-fetch.ts +212 -0
- package/src/utils/ticker-tokenizer.test.ts +31 -0
- package/src/utils/ticker-tokenizer.ts +7 -42
- package/src/version.ts +1 -1
|
@@ -218,7 +218,7 @@ function makePluginRegistry(hasPaneSettings: (paneId: string) => boolean = () =>
|
|
|
218
218
|
showWidget: () => {},
|
|
219
219
|
updateLayoutFn: () => {},
|
|
220
220
|
getTermSizeFn: () => ({ width: 80, height: 24 }),
|
|
221
|
-
|
|
221
|
+
notify: () => {},
|
|
222
222
|
createPaneFromTemplateFn: () => {},
|
|
223
223
|
createPaneFromTemplateAsyncFn: async () => {},
|
|
224
224
|
openPaneSettingsFn: () => {},
|
|
@@ -352,6 +352,308 @@ describe("CommandBar", () => {
|
|
|
352
352
|
expect(testSetup.captureCharFrame()).not.toContain("Commands");
|
|
353
353
|
});
|
|
354
354
|
|
|
355
|
+
test("runs plugin command shortcuts from the root query", async () => {
|
|
356
|
+
const calls: string[] = [];
|
|
357
|
+
|
|
358
|
+
testSetup = await testRender(<CommandBarHarness
|
|
359
|
+
query="GL"
|
|
360
|
+
configurePluginRegistry={(pluginRegistry) => {
|
|
361
|
+
(pluginRegistry.commands as Map<string, any>).set("gridlock-all", {
|
|
362
|
+
id: "gridlock-all",
|
|
363
|
+
label: "Gridlock All Windows",
|
|
364
|
+
description: "Arrange all visible panes into a tiled grid",
|
|
365
|
+
keywords: ["grid", "gridlock", "tile", "arrange", "windows", "layout"],
|
|
366
|
+
shortcut: "GL",
|
|
367
|
+
category: "config",
|
|
368
|
+
execute: async () => {
|
|
369
|
+
calls.push("gridlock-all");
|
|
370
|
+
},
|
|
371
|
+
});
|
|
372
|
+
(pluginRegistry.allPlugins as Map<string, any>).set("layout-manager", {
|
|
373
|
+
id: "layout-manager",
|
|
374
|
+
name: "Layout Manager",
|
|
375
|
+
version: "1.0.0",
|
|
376
|
+
description: "Pane layout management commands",
|
|
377
|
+
});
|
|
378
|
+
const getCommandPluginId = pluginRegistry.getCommandPluginId;
|
|
379
|
+
pluginRegistry.getCommandPluginId = (commandId: string) => (
|
|
380
|
+
commandId === "gridlock-all" ? "layout-manager" : getCommandPluginId(commandId)
|
|
381
|
+
);
|
|
382
|
+
}}
|
|
383
|
+
/>, {
|
|
384
|
+
width: 80,
|
|
385
|
+
height: 24,
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
await testSetup.renderOnce();
|
|
389
|
+
|
|
390
|
+
const frame = testSetup.captureCharFrame();
|
|
391
|
+
expect(frame).toContain("Gridlock All Windows");
|
|
392
|
+
expect(frame).toContain("GL");
|
|
393
|
+
|
|
394
|
+
await act(async () => {
|
|
395
|
+
testSetup!.mockInput.pressEnter();
|
|
396
|
+
await Bun.sleep(0);
|
|
397
|
+
await testSetup!.renderOnce();
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
expect(calls).toEqual(["gridlock-all"]);
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
test("surfaces plugin commands by add-style search terms", async () => {
|
|
404
|
+
testSetup = await testRender(<CommandBarHarness
|
|
405
|
+
query="add alert"
|
|
406
|
+
configurePluginRegistry={(pluginRegistry) => {
|
|
407
|
+
(pluginRegistry.commands as Map<string, any>).set("set-alert", {
|
|
408
|
+
id: "set-alert",
|
|
409
|
+
label: "Add Alert",
|
|
410
|
+
description: "Create a price alert from a symbol, condition, and target price",
|
|
411
|
+
keywords: ["add", "set", "alert", "price", "trigger"],
|
|
412
|
+
shortcut: "SA",
|
|
413
|
+
category: "data",
|
|
414
|
+
execute: async () => {},
|
|
415
|
+
});
|
|
416
|
+
}}
|
|
417
|
+
/>, {
|
|
418
|
+
width: 80,
|
|
419
|
+
height: 24,
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
await testSetup.renderOnce();
|
|
423
|
+
|
|
424
|
+
const frame = testSetup.captureCharFrame();
|
|
425
|
+
expect(frame).toContain("Add Alert");
|
|
426
|
+
expect(frame).toContain("SA");
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
test("opens plugin command shortcut arguments in the wizard for confirmation", async () => {
|
|
430
|
+
const calls: Array<Record<string, string> | undefined> = [];
|
|
431
|
+
|
|
432
|
+
testSetup = await testRender(<CommandBarHarness
|
|
433
|
+
query="SA AAPL above 200"
|
|
434
|
+
configurePluginRegistry={(pluginRegistry) => {
|
|
435
|
+
(pluginRegistry.commands as Map<string, any>).set("set-alert", {
|
|
436
|
+
id: "set-alert",
|
|
437
|
+
label: "Add Alert",
|
|
438
|
+
description: "Create a price alert from a symbol, condition, and target price",
|
|
439
|
+
keywords: ["add", "set", "alert", "price", "trigger"],
|
|
440
|
+
shortcut: "SA",
|
|
441
|
+
shortcutArg: {
|
|
442
|
+
placeholder: "symbol condition price",
|
|
443
|
+
kind: "text",
|
|
444
|
+
parse: (arg: string) => {
|
|
445
|
+
const [symbol, condition, price] = arg.split(/\s+/);
|
|
446
|
+
return { symbol, condition, price };
|
|
447
|
+
},
|
|
448
|
+
},
|
|
449
|
+
category: "data",
|
|
450
|
+
wizardLayout: "form",
|
|
451
|
+
wizard: [
|
|
452
|
+
{ key: "symbol", label: "Symbol", type: "text" },
|
|
453
|
+
{
|
|
454
|
+
key: "condition",
|
|
455
|
+
label: "Condition",
|
|
456
|
+
type: "select",
|
|
457
|
+
options: [
|
|
458
|
+
{ label: "Above", value: "above" },
|
|
459
|
+
{ label: "Below", value: "below" },
|
|
460
|
+
],
|
|
461
|
+
},
|
|
462
|
+
{ key: "price", label: "Target Price", type: "number" },
|
|
463
|
+
],
|
|
464
|
+
execute: async (values?: Record<string, string>) => {
|
|
465
|
+
calls.push(values);
|
|
466
|
+
},
|
|
467
|
+
});
|
|
468
|
+
}}
|
|
469
|
+
/>, {
|
|
470
|
+
width: 80,
|
|
471
|
+
height: 24,
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
await testSetup.renderOnce();
|
|
475
|
+
|
|
476
|
+
const frame = testSetup.captureCharFrame();
|
|
477
|
+
expect(frame).toContain("Add Alert");
|
|
478
|
+
expect(frame).toContain("AAPL above 200");
|
|
479
|
+
|
|
480
|
+
await act(async () => {
|
|
481
|
+
testSetup!.mockInput.pressEnter();
|
|
482
|
+
await Bun.sleep(0);
|
|
483
|
+
await testSetup!.renderOnce();
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
const workflowFrame = await waitForFrameToContain("Target Price");
|
|
487
|
+
expect(workflowFrame).toContain("AAPL");
|
|
488
|
+
expect(workflowFrame).toContain("Above");
|
|
489
|
+
expect(workflowFrame).toContain("200");
|
|
490
|
+
expect(calls).toEqual([]);
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
test("opens partial plugin command shortcut arguments in the wizard", async () => {
|
|
494
|
+
testSetup = await testRender(<CommandBarHarness
|
|
495
|
+
query="SA AMD"
|
|
496
|
+
configurePluginRegistry={(pluginRegistry) => {
|
|
497
|
+
(pluginRegistry.commands as Map<string, any>).set("set-alert", {
|
|
498
|
+
id: "set-alert",
|
|
499
|
+
label: "Add Alert",
|
|
500
|
+
description: "Create a price alert from a symbol, condition, and target price",
|
|
501
|
+
keywords: ["add", "set", "alert", "price", "trigger"],
|
|
502
|
+
shortcut: "SA",
|
|
503
|
+
shortcutArg: {
|
|
504
|
+
placeholder: "symbol condition price",
|
|
505
|
+
kind: "text",
|
|
506
|
+
parse: (arg: string) => ({ symbol: arg.trim().toUpperCase() }),
|
|
507
|
+
},
|
|
508
|
+
category: "data",
|
|
509
|
+
wizardLayout: "form",
|
|
510
|
+
wizard: [
|
|
511
|
+
{ key: "symbol", label: "Symbol", type: "text" },
|
|
512
|
+
{
|
|
513
|
+
key: "condition",
|
|
514
|
+
label: "Condition",
|
|
515
|
+
type: "select",
|
|
516
|
+
options: [{ label: "Above", value: "above" }],
|
|
517
|
+
},
|
|
518
|
+
{ key: "price", label: "Target Price", type: "number" },
|
|
519
|
+
],
|
|
520
|
+
execute: async () => {},
|
|
521
|
+
});
|
|
522
|
+
}}
|
|
523
|
+
/>, {
|
|
524
|
+
width: 80,
|
|
525
|
+
height: 24,
|
|
526
|
+
});
|
|
527
|
+
|
|
528
|
+
await testSetup.renderOnce();
|
|
529
|
+
|
|
530
|
+
await act(async () => {
|
|
531
|
+
testSetup!.mockInput.pressEnter();
|
|
532
|
+
await Bun.sleep(0);
|
|
533
|
+
await testSetup!.renderOnce();
|
|
534
|
+
});
|
|
535
|
+
|
|
536
|
+
const workflowFrame = await waitForFrameToContain("Target Price");
|
|
537
|
+
expect(workflowFrame).toContain("AMD");
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
test("updates workflow select fields from the option picker", async () => {
|
|
541
|
+
testSetup = await testRender(<CommandBarHarness
|
|
542
|
+
query="SA AMD"
|
|
543
|
+
configurePluginRegistry={(pluginRegistry) => {
|
|
544
|
+
(pluginRegistry.commands as Map<string, any>).set("set-alert", {
|
|
545
|
+
id: "set-alert",
|
|
546
|
+
label: "Add Alert",
|
|
547
|
+
description: "Create a price alert from a symbol, condition, and target price",
|
|
548
|
+
keywords: ["add", "set", "alert", "price", "trigger"],
|
|
549
|
+
shortcut: "SA",
|
|
550
|
+
shortcutArg: {
|
|
551
|
+
placeholder: "symbol condition price",
|
|
552
|
+
kind: "text",
|
|
553
|
+
parse: (arg: string) => ({ symbol: arg.trim().toUpperCase() }),
|
|
554
|
+
},
|
|
555
|
+
category: "data",
|
|
556
|
+
wizardLayout: "form",
|
|
557
|
+
wizard: [
|
|
558
|
+
{ key: "symbol", label: "Symbol", type: "text" },
|
|
559
|
+
{
|
|
560
|
+
key: "condition",
|
|
561
|
+
label: "Condition",
|
|
562
|
+
type: "select",
|
|
563
|
+
options: [
|
|
564
|
+
{ label: "Above", value: "above" },
|
|
565
|
+
{ label: "Below", value: "below" },
|
|
566
|
+
{ label: "Crosses", value: "crosses" },
|
|
567
|
+
],
|
|
568
|
+
},
|
|
569
|
+
{ key: "price", label: "Target Price", type: "number" },
|
|
570
|
+
],
|
|
571
|
+
execute: async () => {},
|
|
572
|
+
});
|
|
573
|
+
}}
|
|
574
|
+
/>, {
|
|
575
|
+
width: 80,
|
|
576
|
+
height: 24,
|
|
577
|
+
});
|
|
578
|
+
|
|
579
|
+
await testSetup.renderOnce();
|
|
580
|
+
await act(async () => {
|
|
581
|
+
testSetup!.mockInput.pressEnter();
|
|
582
|
+
await Bun.sleep(0);
|
|
583
|
+
await testSetup!.renderOnce();
|
|
584
|
+
});
|
|
585
|
+
await waitForFrameToContain("Target Price");
|
|
586
|
+
|
|
587
|
+
await act(async () => {
|
|
588
|
+
testSetup!.mockInput.pressTab();
|
|
589
|
+
await testSetup!.renderOnce();
|
|
590
|
+
});
|
|
591
|
+
await act(async () => {
|
|
592
|
+
testSetup!.mockInput.pressEnter();
|
|
593
|
+
await testSetup!.renderOnce();
|
|
594
|
+
});
|
|
595
|
+
let frame = await waitForFrameToContain("Below");
|
|
596
|
+
expect(frame).toContain("Crosses");
|
|
597
|
+
|
|
598
|
+
await act(async () => {
|
|
599
|
+
testSetup!.mockInput.pressArrow("down");
|
|
600
|
+
await testSetup!.renderOnce();
|
|
601
|
+
});
|
|
602
|
+
await act(async () => {
|
|
603
|
+
testSetup!.mockInput.pressEnter();
|
|
604
|
+
await testSetup!.renderOnce();
|
|
605
|
+
});
|
|
606
|
+
|
|
607
|
+
frame = await waitForFrameToContain("Target Price");
|
|
608
|
+
expect(frame).toContain("Below");
|
|
609
|
+
});
|
|
610
|
+
|
|
611
|
+
test("opens plugin command workflows from a launch request", async () => {
|
|
612
|
+
testSetup = await testRender(<CommandBarHarness
|
|
613
|
+
query=""
|
|
614
|
+
configureState={(state) => ({
|
|
615
|
+
...state,
|
|
616
|
+
commandBarLaunchRequest: {
|
|
617
|
+
kind: "plugin-command",
|
|
618
|
+
commandId: "set-alert",
|
|
619
|
+
sequence: 1,
|
|
620
|
+
},
|
|
621
|
+
})}
|
|
622
|
+
configurePluginRegistry={(pluginRegistry) => {
|
|
623
|
+
(pluginRegistry.commands as Map<string, any>).set("set-alert", {
|
|
624
|
+
id: "set-alert",
|
|
625
|
+
label: "Set Alert",
|
|
626
|
+
keywords: ["alert", "price", "trigger"],
|
|
627
|
+
shortcut: "SA",
|
|
628
|
+
category: "data",
|
|
629
|
+
wizardLayout: "form",
|
|
630
|
+
wizard: [
|
|
631
|
+
{ key: "symbol", label: "Symbol", type: "text" },
|
|
632
|
+
{
|
|
633
|
+
key: "condition",
|
|
634
|
+
label: "Condition",
|
|
635
|
+
type: "select",
|
|
636
|
+
options: [
|
|
637
|
+
{ label: "Above", value: "above" },
|
|
638
|
+
{ label: "Below", value: "below" },
|
|
639
|
+
],
|
|
640
|
+
},
|
|
641
|
+
{ key: "price", label: "Target Price", type: "number" },
|
|
642
|
+
],
|
|
643
|
+
execute: async () => {},
|
|
644
|
+
});
|
|
645
|
+
}}
|
|
646
|
+
/>, {
|
|
647
|
+
width: 80,
|
|
648
|
+
height: 24,
|
|
649
|
+
});
|
|
650
|
+
|
|
651
|
+
const frame = await waitForFrameToContain("Target Price");
|
|
652
|
+
expect(frame).toContain("Set Alert");
|
|
653
|
+
expect(frame).toContain("Symbol");
|
|
654
|
+
expect(frame).toContain("Condition");
|
|
655
|
+
});
|
|
656
|
+
|
|
355
657
|
test("renders theme prefix results in the root query", async () => {
|
|
356
658
|
testSetup = await testRender(<CommandBarHarness query="TH " />, {
|
|
357
659
|
width: 80,
|
|
@@ -659,11 +961,42 @@ describe("CommandBar", () => {
|
|
|
659
961
|
expect(saved.at(-1)?.metadata.watchlists).toEqual(["watchlist"]);
|
|
660
962
|
});
|
|
661
963
|
|
|
662
|
-
test("bare AW without a compatible active target
|
|
964
|
+
test("bare AW without a compatible active target adds to the sole watchlist directly", async () => {
|
|
965
|
+
const saved: TickerRecord[] = [];
|
|
966
|
+
|
|
663
967
|
testSetup = await testRender(
|
|
664
968
|
<CommandBarHarness
|
|
665
969
|
query="AW"
|
|
666
970
|
selectedTicker="AAPL"
|
|
971
|
+
onSaveTicker={(ticker) => {
|
|
972
|
+
saved.push(ticker);
|
|
973
|
+
}}
|
|
974
|
+
/>,
|
|
975
|
+
{ width: 100, height: 20 },
|
|
976
|
+
);
|
|
977
|
+
|
|
978
|
+
await testSetup.renderOnce();
|
|
979
|
+
await act(async () => {
|
|
980
|
+
testSetup!.mockInput.pressEnter();
|
|
981
|
+
await Bun.sleep(0);
|
|
982
|
+
await testSetup!.renderOnce();
|
|
983
|
+
});
|
|
984
|
+
|
|
985
|
+
expect(saved.at(-1)?.metadata.watchlists).toEqual(["watchlist"]);
|
|
986
|
+
});
|
|
987
|
+
|
|
988
|
+
test("bare AW without a compatible active target opens inline target selection when multiple watchlists exist", async () => {
|
|
989
|
+
testSetup = await testRender(
|
|
990
|
+
<CommandBarHarness
|
|
991
|
+
query="AW"
|
|
992
|
+
selectedTicker="AAPL"
|
|
993
|
+
configureConfig={(config) => ({
|
|
994
|
+
...config,
|
|
995
|
+
watchlists: [
|
|
996
|
+
{ id: "watchlist", name: "Watchlist" },
|
|
997
|
+
{ id: "growth", name: "Growth Radar" },
|
|
998
|
+
],
|
|
999
|
+
})}
|
|
667
1000
|
/>,
|
|
668
1001
|
{ width: 100, height: 20 },
|
|
669
1002
|
);
|
|
@@ -710,7 +1043,6 @@ describe("CommandBar", () => {
|
|
|
710
1043
|
|
|
711
1044
|
const frame = testSetup.captureCharFrame();
|
|
712
1045
|
expect(frame).toContain("Add AAPL to Portfolio");
|
|
713
|
-
expect(frame).toContain('in "Research"');
|
|
714
1046
|
});
|
|
715
1047
|
|
|
716
1048
|
test("AP opens the add-to-portfolio workflow and prefills avg cost from the current price", async () => {
|
|
@@ -720,7 +1052,7 @@ describe("CommandBar", () => {
|
|
|
720
1052
|
selectedTicker="AAPL"
|
|
721
1053
|
configureConfig={(config) => ({
|
|
722
1054
|
...config,
|
|
723
|
-
portfolios: [{ id: "research", name: "
|
|
1055
|
+
portfolios: [{ id: "research", name: "Only Manual Portfolio", currency: "USD" }],
|
|
724
1056
|
})}
|
|
725
1057
|
configureState={(state) => ({
|
|
726
1058
|
...state,
|
|
@@ -762,6 +1094,7 @@ describe("CommandBar", () => {
|
|
|
762
1094
|
expect(frame).toContain("Shares");
|
|
763
1095
|
expect(frame).toContain("Avg Cost");
|
|
764
1096
|
expect(frame).toContain("205.5");
|
|
1097
|
+
expect(frame).not.toContain("Only Manual Portfolio");
|
|
765
1098
|
expectSingleBackControl(frame);
|
|
766
1099
|
});
|
|
767
1100
|
|
|
@@ -873,7 +1206,6 @@ describe("CommandBar", () => {
|
|
|
873
1206
|
|
|
874
1207
|
const frame = testSetup.captureCharFrame();
|
|
875
1208
|
expect(frame).toContain("Set Position for AAPL");
|
|
876
|
-
expect(frame).toContain('in "Research"');
|
|
877
1209
|
});
|
|
878
1210
|
|
|
879
1211
|
test("prefills the portfolio position workflow from the active manual portfolio and ticker", async () => {
|