gloomberb 0.7.2 → 0.7.3

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.
Files changed (129) hide show
  1. package/README.md +79 -132
  2. package/package.json +1 -1
  3. package/src/app.tsx +73 -67
  4. package/src/components/chart/chart-data.ts +7 -2
  5. package/src/components/chart/chart-pane-settings.ts +7 -4
  6. package/src/components/chart/chart-renderer.ts +49 -15
  7. package/src/components/chart/chart-types.ts +2 -2
  8. package/src/components/chart/chart.test.ts +27 -8
  9. package/src/components/chart/comparison-stock-chart.tsx +84 -121
  10. package/src/components/chart/native/chart-rasterizer.ts +43 -17
  11. package/src/components/chart/price-axis-labels.tsx +25 -9
  12. package/src/components/chart/stock-chart-renderer-switch.test.tsx +1 -1
  13. package/src/components/chart/stock-chart.tsx +59 -41
  14. package/src/components/command-bar/command-bar.test.tsx +446 -120
  15. package/src/components/command-bar/command-bar.tsx +528 -383
  16. package/src/components/command-bar/command-registry.ts +16 -6
  17. package/src/components/command-bar/root-shortcuts.ts +4 -5
  18. package/src/components/command-bar/view-model.test.ts +1 -0
  19. package/src/components/command-bar/view-model.ts +2 -1
  20. package/src/components/command-bar/workflow-ops.ts +11 -32
  21. package/src/components/data-table-view.test.tsx +24 -1
  22. package/src/components/data-table-view.tsx +3 -2
  23. package/src/components/feed-data-table-stack-view.tsx +3 -2
  24. package/src/components/layout/detached-pane-shell.tsx +2 -2
  25. package/src/components/layout/floating-pane.tsx +9 -2
  26. package/src/components/layout/pane-footer.tsx +1 -1
  27. package/src/components/layout/pane-header.tsx +4 -2
  28. package/src/components/layout/pane-sizing.ts +12 -0
  29. package/src/components/layout/pane.tsx +24 -2
  30. package/src/components/layout/shell.tsx +24 -10
  31. package/src/components/layout/status-bar.test.tsx +4 -1
  32. package/src/components/layout/status-bar.tsx +4 -24
  33. package/src/components/markdown-text.tsx +53 -8
  34. package/src/components/onboarding/onboarding-wizard.tsx +7 -6
  35. package/src/components/pane-settings-dialog.tsx +9 -6
  36. package/src/components/pane-template-wizard.tsx +3 -2
  37. package/src/components/price-selector-dialog.tsx +3 -2
  38. package/src/components/price-sparkline-view.tsx +463 -0
  39. package/src/components/price-sparkline.ts +46 -0
  40. package/src/components/table-view-shared.tsx +21 -3
  41. package/src/components/ticker-list-table-view.tsx +3 -2
  42. package/src/components/ticker-list-table.tsx +11 -51
  43. package/src/components/toggle-list.tsx +3 -3
  44. package/src/components/ui/choice-dialog.tsx +3 -2
  45. package/src/components/ui/multi-select-dialog.tsx +3 -2
  46. package/src/components/ui/native-select.tsx +3 -3
  47. package/src/core/state/app-state.ts +210 -80
  48. package/src/data/config-store-node.ts +113 -25
  49. package/src/data/config-store.test.ts +65 -3
  50. package/src/data/plugin-state-store.ts +39 -13
  51. package/src/data/sqlite-cache.test.ts +13 -0
  52. package/src/market-data/coordinator.ts +8 -1
  53. package/src/news/aggregator.test.ts +41 -0
  54. package/src/news/aggregator.ts +61 -9
  55. package/src/plugins/builtin/ai/ask-ai-detail-tab.tsx +25 -6
  56. package/src/plugins/builtin/ai/settings.ts +3 -0
  57. package/src/plugins/builtin/broker-manager/index.tsx +4 -3
  58. package/src/plugins/builtin/chat-controller.test.ts +398 -17
  59. package/src/plugins/builtin/chat-controller.ts +258 -44
  60. package/src/plugins/builtin/chat.test.tsx +257 -6
  61. package/src/plugins/builtin/chat.tsx +225 -60
  62. package/src/plugins/builtin/comparison-chart.test.tsx +117 -3
  63. package/src/plugins/builtin/correlation/colors.test.ts +39 -0
  64. package/src/plugins/builtin/correlation/colors.ts +87 -0
  65. package/src/plugins/builtin/correlation/index.test.tsx +151 -0
  66. package/src/plugins/builtin/correlation/index.tsx +92 -21
  67. package/src/plugins/builtin/debug.tsx +4 -3
  68. package/src/plugins/builtin/econ/index.tsx +3 -2
  69. package/src/plugins/builtin/help.test.tsx +2 -2
  70. package/src/plugins/builtin/holders/index.tsx +25 -13
  71. package/src/plugins/builtin/layout-manager.tsx +1 -7
  72. package/src/plugins/builtin/news-wire/index.tsx +1 -1
  73. package/src/plugins/builtin/news-wire/news-detail-view.tsx +3 -2
  74. package/src/plugins/builtin/news-wire/news-preset-pane.tsx +4 -1
  75. package/src/plugins/builtin/news-wire/persisted-articles.ts +7 -1
  76. package/src/plugins/builtin/options.tsx +9 -17
  77. package/src/plugins/builtin/portfolio-list/cli/commands.ts +6 -10
  78. package/src/plugins/builtin/portfolio-list/metrics.ts +11 -0
  79. package/src/plugins/builtin/portfolio-list/mutations.ts +17 -0
  80. package/src/plugins/builtin/portfolio-list/pane.tsx +117 -18
  81. package/src/plugins/builtin/portfolio-list/quick-add.tsx +422 -0
  82. package/src/plugins/builtin/portfolio-list/settings.ts +20 -12
  83. package/src/plugins/builtin/portfolio-list/table.tsx +3 -3
  84. package/src/plugins/builtin/portfolio-list.test.tsx +282 -2
  85. package/src/plugins/builtin/quote-monitor.test.tsx +158 -25
  86. package/src/plugins/builtin/sectors/index.tsx +252 -41
  87. package/src/plugins/builtin/sectors/sector-data.ts +41 -1
  88. package/src/plugins/builtin/ticker-detail/chart-tab.tsx +3 -2
  89. package/src/plugins/builtin/ticker-detail/index.tsx +30 -9
  90. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +25 -15
  91. package/src/plugins/builtin/ticker-detail/pane.tsx +0 -6
  92. package/src/plugins/builtin/ticker-detail/quote-monitor.tsx +442 -63
  93. package/src/plugins/builtin/ticker-detail/settings.ts +84 -3
  94. package/src/plugins/builtin/ticker-detail.test.tsx +2 -2
  95. package/src/plugins/ibkr/trading-pane.tsx +3 -2
  96. package/src/plugins/plugin-runtime.tsx +2 -2
  97. package/src/plugins/prediction-markets/settings.ts +4 -0
  98. package/src/plugins/registry.test.ts +55 -0
  99. package/src/plugins/registry.ts +11 -4
  100. package/src/plugins/ticker-navigation.test.ts +35 -5
  101. package/src/plugins/ticker-navigation.ts +16 -22
  102. package/src/renderers/electrobun/bun/application-menu-click.test.ts +9 -0
  103. package/src/renderers/electrobun/bun/application-menu-click.ts +7 -4
  104. package/src/renderers/electrobun/bun/application-menu.ts +6 -1
  105. package/src/renderers/electrobun/bun/desktop-workspace.ts +47 -29
  106. package/src/renderers/electrobun/bun/index.ts +52 -13
  107. package/src/renderers/electrobun/view/app-services.ts +51 -9
  108. package/src/renderers/electrobun/view/backend-rpc.ts +5 -8
  109. package/src/renderers/electrobun/view/desktop-controls.tsx +4 -4
  110. package/src/renderers/electrobun/view/main.tsx +0 -16
  111. package/src/renderers/electrobun/view/styles.css +23 -21
  112. package/src/renderers/electrobun/view/ui-host.tsx +6 -4
  113. package/src/renderers/opentui/host.tsx +2 -1
  114. package/src/renderers/opentui/start.tsx +1 -1
  115. package/src/renderers/opentui/test-utils.tsx +6 -5
  116. package/src/state/app-bootstrap.ts +3 -3
  117. package/src/state/app-context.test.ts +113 -0
  118. package/src/state/app-context.tsx +8 -4
  119. package/src/theme/colors.ts +13 -14
  120. package/src/types/config.ts +9 -4
  121. package/src/types/plugin.ts +8 -1
  122. package/src/ui/context-menu.tsx +4 -4
  123. package/src/utils/api-client.test.ts +128 -0
  124. package/src/utils/api-client.ts +112 -7
  125. package/src/utils/fuzzy-search.ts +12 -1
  126. package/src/utils/keyboard.ts +31 -0
  127. package/src/utils/ticker-search.test.ts +2 -2
  128. package/src/utils/ticker-search.ts +48 -1
  129. package/src/version.ts +1 -1
@@ -6,7 +6,6 @@ import { useShortcut } from "../../react/input";
6
6
  import { useAppDispatch, useAppSelector, usePaneInstance, usePaneInstanceId, usePaneSettingValue, usePaneTicker } from "../../state/app-context";
7
7
  import { usePaneFooter, type PaneFooterSegment, type PaneHint } from "../layout/pane-footer";
8
8
  import { ShortcutHint } from "../ui";
9
- import { saveConfig } from "../../data/config-store";
10
9
  import { getSharedMarketData } from "../../plugins/registry";
11
10
  import { colors } from "../../theme/colors";
12
11
  import { useThemeColors } from "../../theme/theme-context";
@@ -135,6 +134,7 @@ const MODE_CHIPS: Record<ChartRenderMode, string> = {
135
134
  line: "L",
136
135
  candles: "C",
137
136
  ohlc: "O",
137
+ hlc: "H",
138
138
  };
139
139
 
140
140
  const MODE_LABELS: Record<ChartRenderMode, string> = {
@@ -142,6 +142,7 @@ const MODE_LABELS: Record<ChartRenderMode, string> = {
142
142
  line: "LINE",
143
143
  candles: "CANDLES",
144
144
  ohlc: "OHLC",
145
+ hlc: "HLC",
145
146
  };
146
147
 
147
148
  const AXIS_MEASURE_PALETTE = resolveChartPalette({
@@ -1151,9 +1152,18 @@ function resolveSelectionCursor(
1151
1152
  };
1152
1153
  }
1153
1154
 
1154
- const INDICATOR_COLORS = [
1155
- "#FF6B6B", "#4ECDC4", "#45B7D1", "#96CEB4", "#FFEAA7", "#DDA0DD", "#98D8C8",
1156
- ];
1155
+ function getIndicatorColor(index: number): string {
1156
+ const indicatorColors = [
1157
+ colors.negative,
1158
+ colors.positive,
1159
+ colors.borderFocused,
1160
+ colors.warning,
1161
+ colors.textBright,
1162
+ colors.neutral,
1163
+ colors.textMuted,
1164
+ ];
1165
+ return indicatorColors[((index % indicatorColors.length) + indicatorColors.length) % indicatorColors.length]!;
1166
+ }
1157
1167
 
1158
1168
  function getIndicatorWarmupPeriod(config: IndicatorConfig): number {
1159
1169
  const periods = [
@@ -1269,7 +1279,7 @@ function computeIndicatorOverlays(
1269
1279
  config: IndicatorConfig,
1270
1280
  ): ChartIndicatorOverlays {
1271
1281
  let colorIdx = 0;
1272
- const nextColor = () => INDICATOR_COLORS[colorIdx++ % INDICATOR_COLORS.length]!;
1282
+ const nextColor = () => getIndicatorColor(colorIdx++);
1273
1283
 
1274
1284
  const smaLines = (config.sma ?? []).map((period) => ({
1275
1285
  period,
@@ -1439,7 +1449,7 @@ export const ResolvedStockChart = memo(function ResolvedStockChart({
1439
1449
  }: ResolvedStockChartProps) {
1440
1450
  const themeColors = useThemeColors();
1441
1451
  const renderer = useNativeRenderer();
1442
- const { canvasCharts, cellWidthPx = 8, cellHeightPx = 18, pixelRatio = 1 } = useUiCapabilities();
1452
+ const { canvasCharts, cellWidthPx = 8, cellHeightPx = 18, pixelRatio = 1, fractionalViewport = false } = useUiCapabilities();
1443
1453
  const dispatch = useAppDispatch();
1444
1454
  const config = useAppSelector((state) => state.config);
1445
1455
  const paneId = usePaneInstanceId();
@@ -1449,6 +1459,7 @@ export const ResolvedStockChart = memo(function ResolvedStockChart({
1449
1459
  const preferredRenderer = config.chartPreferences.renderer;
1450
1460
  const [storedRangePreset] = usePaneSettingValue("chartRangePreset", DEFAULT_TICKER_CHART_RANGE_PRESET);
1451
1461
  const [storedResolution] = usePaneSettingValue<ChartResolution>("chartResolution", DEFAULT_TICKER_CHART_RESOLUTION);
1462
+ const [storedRenderMode, setStoredRenderMode] = usePaneSettingValue<ChartRenderMode>("chartRenderMode", defaultRenderMode);
1452
1463
  const persistChartControls = usePersistChartControlSelection("chartRangePreset");
1453
1464
  const [viewState, setViewState] = useState<StockChartViewportState>({
1454
1465
  presetRange: compact ? "1Y" : storedRangePreset,
@@ -1458,7 +1469,7 @@ export const ResolvedStockChart = memo(function ResolvedStockChart({
1458
1469
  zoomLevel: 1,
1459
1470
  cursorX: null,
1460
1471
  cursorY: null,
1461
- renderMode: defaultRenderMode,
1472
+ renderMode: storedRenderMode,
1462
1473
  });
1463
1474
  // Read indicator config from the chart caller, falling back to legacy pane settings.
1464
1475
  const indicatorConfig: IndicatorConfig = indicatorConfigOverride ?? ((pane?.settings?.indicators as IndicatorConfig) ?? EMPTY_INDICATOR_CONFIG);
@@ -1683,6 +1694,12 @@ export const ResolvedStockChart = memo(function ResolvedStockChart({
1683
1694
  });
1684
1695
  updateDisplayCursorTarget(EMPTY_DISPLAY_CURSOR, "discrete");
1685
1696
  }, [compact, selectionSupportMap, storedRangePreset, storedResolution]);
1697
+ useEffect(() => {
1698
+ if (compact) return;
1699
+ setViewState((current) => (
1700
+ current.renderMode === storedRenderMode ? current : { ...current, renderMode: storedRenderMode }
1701
+ ));
1702
+ }, [compact, storedRenderMode]);
1686
1703
  const effectiveResolution: ChartResolution = !compact
1687
1704
  && requestedResolution !== "auto"
1688
1705
  && resolutionSupport !== null
@@ -1724,9 +1741,9 @@ export const ResolvedStockChart = memo(function ResolvedStockChart({
1724
1741
  const axisSectionWidthBudget = compact
1725
1742
  ? axisMode === "percent" ? 11 : 8
1726
1743
  : axisMode === "percent" ? 11 : 10;
1727
- const axisRightPadding = 1;
1744
+ const axisRightPadding = compact || fractionalViewport ? 0 : 1;
1728
1745
  const minimumAxisWidth = axisMode === "percent" ? 5 : 4;
1729
- const axisGap = axisSectionWidthBudget > 0 ? 1 : 0;
1746
+ const axisGap = axisSectionWidthBudget > 0 ? fractionalViewport ? 0.5 : 1 : 0;
1730
1747
  const minChartWidth = compact ? 12 : 20;
1731
1748
  const measurementChartWidth = Math.max(width - axisSectionWidthBudget - axisGap, minChartWidth);
1732
1749
  const headerRows = compact ? 0 : 2;
@@ -1734,7 +1751,7 @@ export const ResolvedStockChart = memo(function ResolvedStockChart({
1734
1751
  const timeAxisRow = 1;
1735
1752
  // Native/canvas surfaces can cover the last physical row after pixel rounding;
1736
1753
  // keep the text x-axis one row clear of the pane footer.
1737
- const nativeSurfaceGuardRow = !compact && (useCanvasChart || effectiveRenderer === "kitty") ? 1 : 0;
1754
+ const nativeSurfaceGuardRow = !compact && fractionalViewport && (useCanvasChart || effectiveRenderer === "kitty") ? 1 : 0;
1738
1755
  const volumeHeight = showVolume && !compact ? 3 : 0;
1739
1756
  const chartHeight = Math.max(height - headerRows - helpRow - timeAxisRow - nativeSurfaceGuardRow, 4);
1740
1757
  const chartCurrency = currencyOverride ?? financials?.quote?.currency ?? ticker?.metadata.currency ?? "USD";
@@ -2360,7 +2377,7 @@ export const ResolvedStockChart = memo(function ResolvedStockChart({
2360
2377
  colors: AXIS_MEASURE_PALETTE,
2361
2378
  timeAxisDates: measuredTimeAxisDates,
2362
2379
  });
2363
- const cursorSamples = measuredScene
2380
+ const cursorSamples = !compact && measuredScene
2364
2381
  ? [
2365
2382
  formatCursorAxisValue(
2366
2383
  measuredScene.min,
@@ -2401,6 +2418,7 @@ export const ResolvedStockChart = memo(function ResolvedStockChart({
2401
2418
  chartHeight,
2402
2419
  compact,
2403
2420
  displayedDateWindow,
2421
+ fractionalViewport,
2404
2422
  history,
2405
2423
  historyOverride,
2406
2424
  minChartWidth,
@@ -2545,18 +2563,11 @@ export const ResolvedStockChart = memo(function ResolvedStockChart({
2545
2563
  };
2546
2564
  }, [preferredRenderer, renderer]);
2547
2565
 
2548
- const persistDefaultRenderMode = (nextMode: ChartRenderMode) => {
2549
- if (nextMode === defaultRenderMode) return;
2550
- const nextConfig = {
2551
- ...config,
2552
- chartPreferences: {
2553
- ...config.chartPreferences,
2554
- defaultRenderMode: nextMode,
2555
- },
2556
- };
2557
- dispatch({ type: "SET_CONFIG", config: nextConfig });
2558
- saveConfig(nextConfig).catch(() => {});
2559
- };
2566
+ const persistRenderMode = useCallback((nextMode: ChartRenderMode) => {
2567
+ if (!compact && nextMode !== storedRenderMode) {
2568
+ setStoredRenderMode(nextMode);
2569
+ }
2570
+ }, [compact, setStoredRenderMode, storedRenderMode]);
2560
2571
 
2561
2572
  const expandBufferRange = (action: PendingExpansionAction): boolean => {
2562
2573
  if (compact) return false;
@@ -2658,7 +2669,7 @@ export const ResolvedStockChart = memo(function ResolvedStockChart({
2658
2669
  };
2659
2670
 
2660
2671
  const setRenderMode = (mode: ChartRenderMode) => {
2661
- persistDefaultRenderMode(mode);
2672
+ persistRenderMode(mode);
2662
2673
  setViewState((current) => ({ ...current, renderMode: mode }));
2663
2674
  };
2664
2675
 
@@ -2872,7 +2883,7 @@ export const ResolvedStockChart = memo(function ResolvedStockChart({
2872
2883
  const activeMode = current.renderMode ?? "area";
2873
2884
  const index = CHART_RENDER_MODES.indexOf(activeMode);
2874
2885
  const nextMode = CHART_RENDER_MODES[(index + 1) % CHART_RENDER_MODES.length]!;
2875
- persistDefaultRenderMode(nextMode);
2886
+ persistRenderMode(nextMode);
2876
2887
  return { ...current, renderMode: nextMode };
2877
2888
  });
2878
2889
  return;
@@ -3412,7 +3423,7 @@ export const ResolvedStockChart = memo(function ResolvedStockChart({
3412
3423
 
3413
3424
  const hasHistory = chartWindow.points.length > 0;
3414
3425
  const requestedMode = projection.requestedMode;
3415
- const showOhlcSummary = projection.effectiveMode === "candles" || projection.effectiveMode === "ohlc";
3426
+ const showOhlcSummary = projection.effectiveMode === "candles" || projection.effectiveMode === "ohlc" || projection.effectiveMode === "hlc";
3416
3427
  const hasDisplayCursor = displayCursorX !== null && displayCursorY !== null;
3417
3428
  const activePoint = showOhlcSummary ? (selectionScene?.activePoint ?? null) : null;
3418
3429
  const visiblePriceRange = selectionScene
@@ -3463,7 +3474,7 @@ export const ResolvedStockChart = memo(function ResolvedStockChart({
3463
3474
  const activeMode = current.renderMode ?? "area";
3464
3475
  const index = CHART_RENDER_MODES.indexOf(activeMode);
3465
3476
  const nextMode = CHART_RENDER_MODES[(index + 1) % CHART_RENDER_MODES.length]!;
3466
- persistDefaultRenderMode(nextMode);
3477
+ persistRenderMode(nextMode);
3467
3478
  return { ...current, renderMode: nextMode };
3468
3479
  });
3469
3480
  };
@@ -3535,6 +3546,7 @@ export const ResolvedStockChart = memo(function ResolvedStockChart({
3535
3546
  footerHints,
3536
3547
  history,
3537
3548
  navigableDateWindow,
3549
+ persistRenderMode,
3538
3550
  resolutionChips,
3539
3551
  selectedResolution,
3540
3552
  selectionSupportMap,
@@ -3552,26 +3564,33 @@ export const ResolvedStockChart = memo(function ResolvedStockChart({
3552
3564
  priceRange: visiblePriceRange,
3553
3565
  });
3554
3566
 
3567
+ const parts: PaneFooterSegment["parts"] = [
3568
+ ...(projection.effectiveMode === "hlc"
3569
+ ? []
3570
+ : [
3571
+ { text: "O", tone: "label" as const },
3572
+ { text: formatPrice(activePoint.open), tone: "value" as const },
3573
+ ]),
3574
+ { text: "H", tone: "label" },
3575
+ { text: formatPrice(activePoint.high), tone: "value" },
3576
+ { text: "L", tone: "label" },
3577
+ { text: formatPrice(activePoint.low), tone: "value" },
3578
+ { text: "C", tone: "label" },
3579
+ { text: formatPrice(activePoint.close), tone: "value" },
3580
+ { text: "V", tone: "label" },
3581
+ { text: formatCompact(activePoint.volume), tone: "value" },
3582
+ ];
3583
+
3555
3584
  return [{
3556
- id: "ohlc",
3557
- parts: [
3558
- { text: "O", tone: "label" },
3559
- { text: formatPrice(activePoint.open), tone: "value" },
3560
- { text: "H", tone: "label" },
3561
- { text: formatPrice(activePoint.high), tone: "value" },
3562
- { text: "L", tone: "label" },
3563
- { text: formatPrice(activePoint.low), tone: "value" },
3564
- { text: "C", tone: "label" },
3565
- { text: formatPrice(activePoint.close), tone: "value" },
3566
- { text: "V", tone: "label" },
3567
- { text: formatCompact(activePoint.volume), tone: "value" },
3568
- ],
3585
+ id: projection.effectiveMode === "hlc" ? "hlc" : "ohlc",
3586
+ parts,
3569
3587
  }];
3570
3588
  }, [
3571
3589
  activePoint,
3572
3590
  chartAssetCategory,
3573
3591
  chartCurrency,
3574
3592
  compact,
3593
+ projection.effectiveMode,
3575
3594
  showOhlcSummary,
3576
3595
  visiblePriceRange,
3577
3596
  ]);
@@ -4062,7 +4081,6 @@ export const ResolvedStockChart = memo(function ResolvedStockChart({
4062
4081
  </Box>
4063
4082
  ) : (
4064
4083
  <Box flexDirection="row" gap={1}>
4065
- <Text fg={colors.textDim}>mode:{MODE_LABELS[requestedMode]}</Text>
4066
4084
  {projection.fallbackMode && (
4067
4085
  <Text fg={colors.textDim}>auto:{MODE_LABELS[projection.fallbackMode]}</Text>
4068
4086
  )}