gloomberb 0.7.2 → 0.7.4

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 (167) 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 +158 -47
  7. package/src/components/chart/chart-types.ts +20 -2
  8. package/src/components/chart/chart.test.ts +179 -13
  9. package/src/components/chart/comparison-chart-renderer.test.ts +14 -30
  10. package/src/components/chart/comparison-chart-renderer.ts +50 -11
  11. package/src/components/chart/comparison-stock-chart.tsx +129 -129
  12. package/src/components/chart/market-session.ts +187 -0
  13. package/src/components/chart/native/chart-rasterizer.ts +108 -19
  14. package/src/components/chart/price-axis-labels.tsx +25 -9
  15. package/src/components/chart/stock-chart-renderer-switch.test.tsx +97 -1
  16. package/src/components/chart/stock-chart.tsx +95 -49
  17. package/src/components/chart/time-axis-label.tsx +56 -2
  18. package/src/components/command-bar/command-bar.test.tsx +446 -120
  19. package/src/components/command-bar/command-bar.tsx +535 -384
  20. package/src/components/command-bar/command-registry.ts +16 -6
  21. package/src/components/command-bar/list-model.ts +8 -4
  22. package/src/components/command-bar/root-shortcuts.ts +4 -5
  23. package/src/components/command-bar/view-model.test.ts +21 -0
  24. package/src/components/command-bar/view-model.ts +17 -4
  25. package/src/components/command-bar/workflow-ops.ts +11 -32
  26. package/src/components/data-table-view.test.tsx +24 -1
  27. package/src/components/data-table-view.tsx +3 -2
  28. package/src/components/feed-data-table-stack-view.tsx +3 -2
  29. package/src/components/layout/detached-pane-shell.tsx +2 -2
  30. package/src/components/layout/floating-pane.tsx +9 -2
  31. package/src/components/layout/pane-footer.tsx +1 -1
  32. package/src/components/layout/pane-header.tsx +4 -2
  33. package/src/components/layout/pane-sizing.ts +12 -0
  34. package/src/components/layout/pane.tsx +24 -2
  35. package/src/components/layout/shell.tsx +24 -10
  36. package/src/components/layout/status-bar.test.tsx +4 -1
  37. package/src/components/layout/status-bar.tsx +4 -24
  38. package/src/components/markdown-text.tsx +53 -8
  39. package/src/components/onboarding/onboarding-wizard.tsx +7 -6
  40. package/src/components/pane-settings-dialog.tsx +9 -6
  41. package/src/components/pane-template-wizard.tsx +3 -2
  42. package/src/components/price-selector-dialog.tsx +3 -2
  43. package/src/components/price-sparkline-view.tsx +463 -0
  44. package/src/components/price-sparkline.ts +46 -0
  45. package/src/components/table-view-shared.tsx +21 -3
  46. package/src/components/ticker-list-table-view.tsx +3 -2
  47. package/src/components/ticker-list-table.tsx +15 -66
  48. package/src/components/toggle-list.tsx +3 -3
  49. package/src/components/ui/choice-dialog.tsx +3 -2
  50. package/src/components/ui/multi-select-dialog.tsx +3 -2
  51. package/src/components/ui/native-select.tsx +3 -3
  52. package/src/core/state/app-state.ts +210 -80
  53. package/src/core/state/session-persistence.ts +25 -0
  54. package/src/data/config-store-node.ts +113 -25
  55. package/src/data/config-store.test.ts +65 -3
  56. package/src/data/plugin-state-store.ts +39 -13
  57. package/src/data/sqlite-cache.test.ts +13 -0
  58. package/src/market-data/coordinator-subscriptions.test.ts +102 -18
  59. package/src/market-data/coordinator.test.ts +122 -2
  60. package/src/market-data/coordinator.ts +200 -56
  61. package/src/market-data/hooks.test.tsx +31 -0
  62. package/src/market-data/hooks.tsx +1 -0
  63. package/src/news/aggregator.test.ts +41 -0
  64. package/src/news/aggregator.ts +61 -9
  65. package/src/plugins/builtin/ai/ask-ai-detail-tab.tsx +25 -6
  66. package/src/plugins/builtin/ai/screener-pane.tsx +3 -0
  67. package/src/plugins/builtin/ai/settings.ts +3 -0
  68. package/src/plugins/builtin/broker-manager/index.tsx +4 -3
  69. package/src/plugins/builtin/chat-controller.test.ts +398 -17
  70. package/src/plugins/builtin/chat-controller.ts +263 -48
  71. package/src/plugins/builtin/chat.test.tsx +312 -6
  72. package/src/plugins/builtin/chat.tsx +245 -66
  73. package/src/plugins/builtin/comparison-chart.test.tsx +117 -3
  74. package/src/plugins/builtin/correlation/colors.test.ts +39 -0
  75. package/src/plugins/builtin/correlation/colors.ts +87 -0
  76. package/src/plugins/builtin/correlation/index.test.tsx +151 -0
  77. package/src/plugins/builtin/correlation/index.tsx +92 -21
  78. package/src/plugins/builtin/debug.tsx +4 -3
  79. package/src/plugins/builtin/econ/index.tsx +3 -2
  80. package/src/plugins/builtin/help.test.tsx +2 -2
  81. package/src/plugins/builtin/holders/index.tsx +25 -13
  82. package/src/plugins/builtin/layout-manager.tsx +1 -7
  83. package/src/plugins/builtin/market-movers/index.tsx +72 -40
  84. package/src/plugins/builtin/news-wire/breaking-pane.test.tsx +156 -0
  85. package/src/plugins/builtin/news-wire/breaking-pane.tsx +0 -90
  86. package/src/plugins/builtin/news-wire/index.tsx +1 -3
  87. package/src/plugins/builtin/news-wire/news-detail-view.tsx +3 -2
  88. package/src/plugins/builtin/news-wire/news-preset-pane.tsx +4 -1
  89. package/src/plugins/builtin/news-wire/persisted-articles.ts +7 -1
  90. package/src/plugins/builtin/options.tsx +9 -17
  91. package/src/plugins/builtin/portfolio-list/cli/commands.ts +6 -10
  92. package/src/plugins/builtin/portfolio-list/metrics.ts +13 -2
  93. package/src/plugins/builtin/portfolio-list/mutations.ts +17 -0
  94. package/src/plugins/builtin/portfolio-list/pane.tsx +139 -23
  95. package/src/plugins/builtin/portfolio-list/quick-add.tsx +422 -0
  96. package/src/plugins/builtin/portfolio-list/settings.ts +20 -12
  97. package/src/plugins/builtin/portfolio-list/table.tsx +3 -3
  98. package/src/plugins/builtin/portfolio-list.test.tsx +311 -9
  99. package/src/plugins/builtin/quote-monitor.test.tsx +158 -25
  100. package/src/plugins/builtin/sectors/index.tsx +275 -43
  101. package/src/plugins/builtin/sectors/sector-data.ts +41 -1
  102. package/src/plugins/builtin/ticker-detail/chart-tab.tsx +3 -2
  103. package/src/plugins/builtin/ticker-detail/index.tsx +30 -9
  104. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +25 -15
  105. package/src/plugins/builtin/ticker-detail/pane.tsx +18 -7
  106. package/src/plugins/builtin/ticker-detail/quote-monitor.tsx +445 -63
  107. package/src/plugins/builtin/ticker-detail/settings.ts +84 -3
  108. package/src/plugins/builtin/ticker-detail.test.tsx +2 -2
  109. package/src/plugins/builtin/world-indices/index.tsx +58 -19
  110. package/src/plugins/ibkr/trading-pane.tsx +3 -2
  111. package/src/plugins/plugin-runtime.tsx +2 -2
  112. package/src/plugins/prediction-markets/settings.ts +4 -0
  113. package/src/plugins/registry.test.ts +55 -0
  114. package/src/plugins/registry.ts +11 -4
  115. package/src/plugins/ticker-navigation.test.ts +35 -5
  116. package/src/plugins/ticker-navigation.ts +16 -22
  117. package/src/renderers/electrobun/bun/application-menu-click.test.ts +9 -0
  118. package/src/renderers/electrobun/bun/application-menu-click.ts +7 -4
  119. package/src/renderers/electrobun/bun/application-menu.ts +6 -1
  120. package/src/renderers/electrobun/bun/desktop-workspace.ts +47 -29
  121. package/src/renderers/electrobun/bun/index.ts +52 -13
  122. package/src/renderers/electrobun/view/app-services.ts +51 -9
  123. package/src/renderers/electrobun/view/backend-rpc.ts +5 -8
  124. package/src/renderers/electrobun/view/desktop-controls.tsx +4 -4
  125. package/src/renderers/electrobun/view/main.tsx +0 -16
  126. package/src/renderers/electrobun/view/styles.css +23 -21
  127. package/src/renderers/electrobun/view/ui-host.tsx +6 -4
  128. package/src/renderers/opentui/host.tsx +2 -1
  129. package/src/renderers/opentui/start.tsx +1 -1
  130. package/src/renderers/opentui/test-utils.tsx +6 -5
  131. package/src/sources/gloomberb-cloud.test.ts +55 -2
  132. package/src/sources/gloomberb-cloud.ts +180 -29
  133. package/src/sources/provider-router.test.ts +567 -10
  134. package/src/sources/provider-router.ts +323 -93
  135. package/src/sources/yahoo-finance.test.ts +37 -0
  136. package/src/sources/yahoo-finance.ts +48 -2
  137. package/src/state/app-bootstrap.test.ts +50 -23
  138. package/src/state/app-bootstrap.ts +29 -13
  139. package/src/state/app-context.test.ts +113 -0
  140. package/src/state/app-context.tsx +8 -4
  141. package/src/state/session-persistence.test.ts +5 -3
  142. package/src/state/use-inline-tickers.ts +3 -0
  143. package/src/state/use-quote-streaming.ts +11 -0
  144. package/src/theme/colors.ts +13 -14
  145. package/src/types/config.ts +9 -4
  146. package/src/types/data-provider.ts +5 -1
  147. package/src/types/financials.ts +1 -0
  148. package/src/types/plugin.ts +8 -1
  149. package/src/ui/context-menu.tsx +4 -4
  150. package/src/utils/api-client.test.ts +248 -0
  151. package/src/utils/api-client.ts +178 -26
  152. package/src/utils/exchanges.test.ts +16 -0
  153. package/src/utils/exchanges.ts +33 -0
  154. package/src/utils/fuzzy-search.ts +12 -1
  155. package/src/utils/keyboard.ts +31 -0
  156. package/src/utils/options.ts +1 -1
  157. package/src/utils/price-history.test.ts +28 -1
  158. package/src/utils/price-history.ts +16 -0
  159. package/src/utils/quote-freshness.test.ts +150 -0
  160. package/src/utils/quote-freshness.ts +42 -1
  161. package/src/utils/quote-resolution.ts +2 -0
  162. package/src/utils/quote-time.test.ts +34 -0
  163. package/src/utils/quote-time.ts +18 -5
  164. package/src/utils/ticker-search.test.ts +2 -2
  165. package/src/utils/ticker-search.ts +48 -1
  166. package/src/version.ts +1 -1
  167. package/src/plugins/builtin/news-wire/digest-store.ts +0 -44
@@ -1,4 +1,4 @@
1
- import { Box, ScrollBox, Text } from "../../../ui";
1
+ import { Box, ScrollBox, Text, useUiCapabilities } from "../../../ui";
2
2
  import { TextAttributes } from "../../../ui";
3
3
  import { useViewport } from "../../../react/input";
4
4
  import { useFxRatesMap } from "../../../market-data/hooks";
@@ -32,7 +32,6 @@ const STAT_COLUMN_GAP = 2;
32
32
  const STAT_LABEL_WIDTH = 12;
33
33
  const BOOK_LABEL_WIDTH = 4;
34
34
  const RANGE_ENDPOINT_WIDTH = 11;
35
- const RANGE_MAX_WIDTH = 42;
36
35
  const POSITION_COLUMN_GAP = 1;
37
36
 
38
37
  function CompactRangeBar({
@@ -71,21 +70,23 @@ function CompactRangeBar({
71
70
  return (
72
71
  <Box flexDirection="column" width={width} flexShrink={0}>
73
72
  <Box flexDirection="row" height={1}>
74
- <Text fg={colors.textDim}>{padTo(label, labelWidth)}</Text>
73
+ <Box width={labelWidth} overflow="hidden">
74
+ <Text fg={colors.textDim}>{label}</Text>
75
+ </Box>
75
76
  <Text fg={markerColor}>{pctLabel}</Text>
76
77
  </Box>
77
78
  <Box flexDirection="row" height={1}>
78
- <Text fg={colors.textDim}>
79
- {padTo(lowText, endpointWidth)}
80
- </Text>
79
+ <Box width={endpointWidth} overflow="hidden">
80
+ <Text fg={colors.textDim}>{lowText}</Text>
81
+ </Box>
81
82
  <Box marginLeft={1} marginRight={1} width={barWidth} flexDirection="row">
82
83
  <Text fg={colors.border}>{"─".repeat(markerIndex)}</Text>
83
84
  <Text fg={markerColor}>{"●"}</Text>
84
85
  <Text fg={colors.border}>{"─".repeat(Math.max(0, barWidth - markerIndex - 1))}</Text>
85
86
  </Box>
86
- <Text fg={colors.textDim}>
87
- {padTo(highText, endpointWidth, "right")}
88
- </Text>
87
+ <Box flexDirection="row" width={endpointWidth} justifyContent="flex-end" overflow="hidden">
88
+ <Text fg={colors.textDim}>{highText}</Text>
89
+ </Box>
89
90
  </Box>
90
91
  </Box>
91
92
  );
@@ -164,7 +165,10 @@ interface PositionColumn {
164
165
 
165
166
  function StatGrid({ fields, width }: { fields: StatField[]; width: number }) {
166
167
  const columnCount = width >= 58 ? 2 : 1;
167
- const colWidth = Math.floor((width - STAT_COLUMN_GAP * (columnCount - 1)) / columnCount);
168
+ const availableWidth = width - STAT_COLUMN_GAP * (columnCount - 1);
169
+ const baseColWidth = Math.floor(availableWidth / columnCount);
170
+ const extraWidth = availableWidth - baseColWidth * columnCount;
171
+ const colWidths = Array.from({ length: columnCount }, (_, index) => baseColWidth + (index === columnCount - 1 ? extraWidth : 0));
168
172
  const rows: Array<Array<StatField | null>> = [];
169
173
  for (let i = 0; i < fields.length; i += columnCount) {
170
174
  rows.push(Array.from({ length: columnCount }, (_, offset) => fields[i + offset] ?? null));
@@ -175,6 +179,7 @@ function StatGrid({ fields, width }: { fields: StatField[]; width: number }) {
175
179
  {rows.map((row, i) => (
176
180
  <Box key={i} flexDirection="row" height={1}>
177
181
  {row.map((field, j) => {
182
+ const colWidth = colWidths[j] ?? baseColWidth;
178
183
  if (!field) {
179
184
  return (
180
185
  <Box key={j} flexDirection="row">
@@ -189,8 +194,12 @@ function StatGrid({ fields, width }: { fields: StatField[]; width: number }) {
189
194
  <Box key={j} flexDirection="row">
190
195
  {j > 0 && <Box width={STAT_COLUMN_GAP} />}
191
196
  <Box width={colWidth} flexDirection="row">
192
- <Text fg={colors.textDim}>{padTo(field.label, labelWidth)}</Text>
193
- <Text fg={field.valueColor ?? colors.text}>{padTo(field.value, valueWidth, "right")}</Text>
197
+ <Box width={labelWidth} overflow="hidden">
198
+ <Text fg={colors.textDim}>{field.label}</Text>
199
+ </Box>
200
+ <Box flexDirection="row" width={valueWidth} justifyContent="flex-end" overflow="hidden">
201
+ <Text fg={field.valueColor ?? colors.text}>{field.value}</Text>
202
+ </Box>
194
203
  </Box>
195
204
  </Box>
196
205
  );
@@ -300,6 +309,7 @@ export function OverviewTab({
300
309
  const baseCurrency = useAppSelector((state) => state.config.baseCurrency);
301
310
  const exchangeRatesState = useAppSelector((state) => state.exchangeRates);
302
311
  const { width: termWidth } = useViewport();
312
+ const { fractionalViewport = false } = useUiCapabilities();
303
313
 
304
314
  if (!ticker) return <EmptyState title="No ticker selected." />;
305
315
 
@@ -336,7 +346,7 @@ export function OverviewTab({
336
346
  routingVenue && routingVenue !== listingVenue ? `route ${routingVenue}` : "",
337
347
  ].filter((part) => part.length > 0);
338
348
 
339
- const contentWidth = Math.max((width || Math.floor(termWidth * 0.5)) - 4, 20);
349
+ const contentWidth = Math.max((width || Math.floor(termWidth * 0.5)) - (fractionalViewport ? 2 : 4), 20);
340
350
  const chartWidth = contentWidth;
341
351
  const hasHistory = (financials?.priceHistory?.length ?? 0) > 2;
342
352
  const hasBidAsk = quote?.bid != null || quote?.ask != null;
@@ -347,8 +357,8 @@ export function OverviewTab({
347
357
  const hasYearRange = quote?.low52w != null && quote?.high52w != null && quote.high52w > quote.low52w;
348
358
  const rangeInline = contentWidth >= 70 && hasDayRange && hasYearRange;
349
359
  const rangeWidth = rangeInline
350
- ? Math.min(RANGE_MAX_WIDTH, Math.floor((contentWidth - 2) / 2))
351
- : Math.min(RANGE_MAX_WIDTH, contentWidth);
360
+ ? Math.floor((contentWidth - 2) / 2)
361
+ : contentWidth;
352
362
  const rangeMarkerColor = quote ? priceColor(quote.change) : colors.textDim;
353
363
 
354
364
  const stats: StatField[] = [];
@@ -62,7 +62,24 @@ export function TickerDetailPane({ focused, width, height }: PaneProps) {
62
62
  const paneInstance = usePaneInstance();
63
63
  const { symbol, ticker, financials } = usePaneTicker();
64
64
  const streamingTarget = quoteSubscriptionTargetFromTicker(ticker, ticker?.metadata.ticker, "provider");
65
- const streamingTargets = useMemo(() => (streamingTarget ? [streamingTarget] : []), [streamingTarget]);
65
+ const streamingTargets = useMemo(() => (
66
+ streamingTarget
67
+ ? [{
68
+ ...streamingTarget,
69
+ surface: "detail" as const,
70
+ visible: true,
71
+ selected: true,
72
+ weight: 100,
73
+ }]
74
+ : []
75
+ ), [
76
+ streamingTarget?.symbol,
77
+ streamingTarget?.exchange,
78
+ streamingTarget?.route,
79
+ streamingTarget?.context?.brokerId,
80
+ streamingTarget?.context?.brokerInstanceId,
81
+ streamingTarget?.context?.instrument,
82
+ ]);
66
83
  useQuoteStreaming(streamingTargets);
67
84
 
68
85
  const { collectionId } = usePaneCollection();
@@ -154,12 +171,6 @@ export function TickerDetailPane({ focused, width, height }: PaneProps) {
154
171
  });
155
172
  }, [resolvedTabId, visibleTabIds]);
156
173
 
157
- useEffect(() => {
158
- if (resolvedTabId !== activeTabId) {
159
- setActiveTabId(resolvedTabId);
160
- }
161
- }, [activeTabId, resolvedTabId, setActiveTabId]);
162
-
163
174
  const handleKeyboard = useCallback((event: { name?: string }) => {
164
175
  const currentState = stateRef.current;
165
176
  if (!currentState.focused || currentState.pluginCaptured) return;